ng-change is not triggered (used along with a directive) - javascript

I have the following html code
<input type="file" ng-model="Import" file-reader="fileContent" ng-change="getList();"/>
As shown above, i am trying to load a text file and get it contents on ng-change.
Here is the directive 'fileReader'
ngUtilityMod.directive('fileReader', function () {
return {
scope: {
fileReader: "="
},
link: function (scope, element) {
$(element).on('change', function (changeEvent) {
var r = new FileReader();
var CSVfile;
var checkCSV = changeEvent.target.files[0].name;
checkCSV = checkCSV.slice(-4);
if (checkCSV === '.csv') {
CSVfile = true;
}
else { CSVfile = false; }
if (changeEvent.target.files[0].type === 'text/plain' || CSVfile === true) {
var files = changeEvent.target.files;
if (files.length) {
r.onload = function (e) {
var contents = e.target.result;
scope.$apply(function () {
scope.fileReader = contents;
});
};
r.readAsText(files[0]);
}
}
else {
'data';
}
});
}
};
});
When ng-change is triggered, i should be able to get to below function. The issue here is that ng-change is not getting triggered at all. If i use ng-click or any other angularjs events, it is able to detect. Can someone please let me know why i am unable to trigger ng-change here
$scope.getList = function () {
$scope.getImport = function (fileContent) {
} // function to load CSV data during import feature.
if (angular.isDefined($scope.fileContent)) {
$scope.Import = $scope.fileContent;
console.log($scope.params);
}
};

Related

Quill.js add a custom javascript function into the editor

I am using Quill.js to have users create custom user designed pages off the main web page. I have a custom slider that I have written in javascript that will take images and rotate through them. I have the toolbar in quill setup to be able to click on the toolbar to setup the slider in a modal window.
When the user clicks to close the modal slider setup window, I'm trying to insert an edit button in the html editor where the cursor sits so the user can edit the information that was just entered or possible delete the button by removing all the information in the slider modal window.
I have written custom blots, followed all the examples I could find and nothing worked. I did get a custom html tag to show, but not a button. When I requested the html from quill when I setup the custom html tag in the editor, all I get is "" from quill.root.innerHTML none of the custom tag or the information in it even though I see it correctly in the editor.
I would like a button in the editor to make it easy to edit the slider data, as there could be more than one. I am not going to limit the number of sliders. It is up to the user to ruin their own page.
I will not be rendering the slider in the edit html window, just trying to display a button to click on. I do give the user a preview button on the modal window to view the slider if they so choose.
I also would like to store the setup information of the slider in a data tag in json format in the button and change that html button to a tag along with the json data when rendering the html in the browser window.
Can this be done in Quill.js?
I did this by using the import blots embed. I don't register as a button but clicking on the blot I do get a link to the embedded data and trigger the edit of the carousel data on that click.
var Quill;
const BlockEmbed = Quill.import("blots/block/embed");
const Link = Quill.import('formats/link');
class Carousel extends BlockEmbed {
static create(value) {
var self = this;
const node = super.create(value);
node.dataset.carousel = JSON.stringify(value);
value.file.frames.forEach(frame => {
const frameDiv = document.createElement("div");
frameDiv.innerText = frame.title;
frameDiv.className += "previewDiv";
node.appendChild(frameDiv);
});
node.onclick = function () {
if (Carousel.onClick) {
Carousel.onClick(self, node);
}
};
return node;
}
static value(domNode) {
return JSON.parse(domNode.dataset.carousel);
}
static onClick: any;
static blotName = "carousel";
static className = "ql-carousel";
static tagName = "DIV";
}
Quill.register("formats/carousel", Carousel);
I then include this as a script on the page where quill is editing the HTML
<script src="~/js/quilljs-carousel.js"></script>
And then this is the custom javascript to handle the events of the blot displayed in a custom modal dialog in a hidden div tag
<script>
function CarouselClicked(blot, node) {
editCarousel(JSON.parse(node.dataset.carousel), node);
}
var Carousel = Quill.import("formats/carousel");
Carousel.onClick = CarouselClicked;
function carouselToolbarClickHandler() {
createCarousel();
}
var Toolbar = Quill.import("modules/toolbar");
Toolbar.DEFAULTS.handlers.carousel = carouselToolbarClickHandler;
$(document).ready(function() {
var div = $("#editor-container");
var Image = Quill.import('formats/image');
Image.className = "img-fluid";
Quill.register(Image, true);
var quill = new Quill(div.get(0),
{
modules: {
syntax: true,
toolbar: '#toolbar-container'
},
theme: 'snow'
});
div.data('quill', quill);
// Only show the toolbar when quill is ready to go
$('#toolbar-container').css('display', 'block');
div.css('display', 'block');
$('#editor-loading').css('display', 'none');
// Override the quill Image handler and create our own.
quill.getModule("toolbar").addHandler("image", imageHandler);
});
function createCarousel() {
$("#carouselModalForm").removeClass("was-validated").get(0).reset();
$("#carouselModalList").empty();
$("#carouselModal")
.data("state", "unsaved")
.one("hidden.bs.modal",
function() {
var data = getCarouselData();
var carouselData = {};
carouselData['file'] = data;
carouselData['speed'] = $('#time').val();
carouselData['height'] = $('#height').val();
carouselData['width'] = $('#width').val();
var quill = $("#editor-container").data().quill;
var range = quill.getSelection(true);
if (range != null) {
quill.insertEmbed(
range.index,
"carousel",
carouselData,
Quill.sources.USER
);
quill.setSelection(range.index + 2, Quill.sources.USER);
}
})
.modal("show");
$('#title').get(0).outerText = "Create Carousel";
}
function editCarousel(value, node) {
$("#carouselModalForm").get(0).reset();
var elem = $("#carouselModalList").empty();
$.each(value.file.frames,
function(i, data) {
$("<option>").appendTo(elem).text(data.title).data("frame", data);
});
$('#time').val(value.speed);
$('#height').val(value.height);
$('#width').val(value.width);
var modal = $("#carouselModal");
modal.find("form").removeClass("was-validated");
modal
.data("state", "unsaved")
.one("hidden.bs.modal",
function() {
if ($("#carouselModal").data("state") !== "saved")
return;
var data = getCarouselData();
var carouselData = {};
carouselData['file'] = data;
carouselData['speed'] = $('#time').val();
carouselData['height'] = $('#height').val();
carouselData['width'] = $('#width').val();
var carousel = Quill.find(node, true);
carousel.replaceWith("carousel", carouselData);
})
.modal("show");
$('#title').get(0).outerText = "Edit Carousel";
}
function getCarouselData() {
var options = $("#carouselModalList").find("option");
var frames = $.map(options,
function(domNode) {
return $(domNode).data("frame");
});
return {
frames : frames
};
}
function getCarouselFrameFormData() {
// Get data from frame
function objectifyForm(formArray) { //serialize data function
var returnArray = {};
for (var i = 0; i < formArray.length; i++) {
returnArray[formArray[i]['name']] = formArray[i]['value'];
}
return returnArray;
}
return objectifyForm($("#carouselFrameModalForm").serializeArray());
}
$("#carouselModalNewFrame").click(function() {
$("#carouselFrameModalForm").removeClass("was-validated").get(0).reset();
$("#backgroundPreview").attr("src", "");
$("#mainPreview").attr("src", "");
$("#carouselFrameModal")
.data("state", "unsaved")
.one("hidden.bs.modal",
function() {
if ($("#carouselFrameModal").data("state") == "saved") {
var data = getCarouselFrameFormData();
$("<option>").appendTo($("#carouselModalList")).text(data.title).data("frame", data);
}
})
.modal("show");
// Fetch all the forms we want to apply custom Bootstrap validation styles to
});
$("#carouselModalEditFrame").click(function () {
var form = $("#carouselFrameModalForm");
form.removeClass("was-validated").get(0).reset();
var selected = $("#carouselModalList option:selected");
var frame = selected.data("frame");
$.each(Object.keys(frame),
function (i, e) {
$("input[name=" + e + "]", form).val(frame[e]);
});
$("#backgroundPreview").attr("src", frame.backgroundImg);
$("#mainPreview").attr("src", frame.mainImg);
$("#carouselFrameModal")
.data("state", "unsaved")
.one("hidden.bs.modal",
function() {
if ($("#carouselFrameModal").data("state") == "saved") {
var data = getCarouselFrameFormData();
selected.text(data.title).data("frame", data);
}
})
.modal("show");
});
$("#carouselModalRemoveFrame").click(function () {
$("#confirm-delete").modal("show");
});
$("#carouselFrameModalForm").find("input:file").change(function() {
var elem = $(this);
var target = elem.data("target");
var preview = elem.data("preview");
FiletoBase64(this, preview, target);
});
$("#carouselModalList").change(function() {
var selected = $("option:selected", this);
$("#carouselModalEditFrame,#carouselModalRemoveFrame").prop("disabled", !selected.length);
});
$("#carouselModalSave").click(function() {
// Validate frameset
var form = $("#carouselModalForm").get(0);
var select = $("#carouselModalList");
if (select.find("option").length == 0) {
select.get(0).setCustomValidity("Need at least one frame");
} else {
select.get(0).setCustomValidity("");
}
if (form.checkValidity()) {
$("#carouselModal").data("state", "saved");
$("#carouselModal").modal("hide");
}
else {
$("#carouselModalForm").addClass("was-validated");
}
});
$("#carouselFrameModalSave").click(function() {
// Validate frame
if ($("#carouselFrameModalForm").get(0).checkValidity()) {
$("#carouselFrameModal").data("state", "saved");
$("#carouselFrameModal").modal("hide");
}
else {
$("#carouselFrameModalForm").addClass("was-validated");
}
});
$('#confirm-delete-delete').click(function () {
$("#carouselModalList option:selected").remove();
$("#confirm-delete").modal("hide");
});
// #region Image FileExplorer Handler
function insertImageToEditor(url) {
var div = $("#editor-container");
var quill = div.data('quill');
var range = quill.getSelection();
quill.insertEmbed(range.index, 'image', url);
}
function CarouselMainimageHandler() {
$("#CarouselMainimageSelectFileExplorer").fileExplorer({
directoryListUrl: '#Url.Action("DirectoryList", "FileTree")',
fileListUrl: '#Url.Action("FileList", "FileTree")'
});
$("#CarouselMainimageSelectModal").modal("show");
}
$("#CarouselMainimageSelectModal").on("hide.bs.modal",
function() {
$("#CarouselMainimageSelectFileExplorer").fileExplorer("destroy");
});
$("#CarouselMainimageSelectSelectButton").click(function() {
var id = $("#CarouselMainimageSelectFileExplorer").fileExplorer("getSelectedFileId");
if (id == null) {
alert("Please select a file");
return;
}
var imageName = $("#CarouselMainimageSelectFileExplorer").fileExplorer("getSelectedFileName");
var imageLink = "#Url.Action("Render", "FileTree")?id=" + id;
$("#mainImageName").val(imageName);
$("#mainImageLink").val(imageLink);
$("#mainImage").attr("src",imageLink);
$("#mainImage").show();
$("#CarouselMainimageSelectModal").modal("hide");
});
function CarouselBackgroundimageHandler() {
$("#CarouselBackgroundimageSelectFileExplorer").fileExplorer({
directoryListUrl: '#Url.Action("DirectoryList", "FileTree")',
fileListUrl: '#Url.Action("FileList", "FileTree")'
});
$("#CarouselBackgroundimageSelectModal").modal("show");
}
$("#CarouselBackgroundimageSelectModal").on("hide.bs.modal",
function() {
$("#CarouselBackgroundimageSelectFileExplorer").fileExplorer("destroy");
});
$("#CarouselBackgroundimageSelectSelectButton").click(function() {
var id = $("#CarouselBackgroundimageSelectFileExplorer").fileExplorer("getSelectedFileId");
if (id == null) {
alert("Please select a file");
return;
}
var imageName = $("#CarouselBackgroundimageSelectFileExplorer").fileExplorer("getSelectedFileName");
var imageLink = "#Url.Action("Render", "FileTree")?id=" + id;
$("#backgroundImageName").val(imageName);
$("#backgroundImageLink").val(imageLink);
$("#backgroundImage").attr("src",imageLink);
$("#backgroundImage").show();
$("#CarouselBackgroundimageSelectModal").modal("hide");
});
function imageHandler() {
$("#imageSelectFileExplorer").fileExplorer({
directoryListUrl: '#Url.Action("DirectoryList", "FileTree")',
fileListUrl: '#Url.Action("FileList", "FileTree")'
});
$("#imageSelectModal").modal("show");
}
$("#imageSelectModal").on("hide.bs.modal",
function() {
$("#imageSelectFileExplorer").fileExplorer("destroy");
});
$("#imageSelectSelectButton").click(function() {
var id = $("#imageSelectFileExplorer").fileExplorer("getSelectedFileId");
if (id == null) {
alert("Please select a file");
return;
}
insertImageToEditor("#Url.Action("Render", "FileTree")?id=" + id);
$("#imageSelectModal").modal("hide");
});
// #endregion
function Save() {
var div = $("#editor-container");
var quill = div.data('quill');
$('#alertSave').show();
$.post({
url: '#Url.Action("Save")',
data: { BodyHtml: quill.root.innerHTML, locationId: #(Model.LocationId?.ToString() ?? "null") },
headers: {
'#Xsrf.HeaderName': '#Xsrf.RequestToken'
}
}).done(function() {
$('#alertSave').hide();
$('#alertSuccess').show();
setTimeout(function() { $('#alertSuccess').hide(); }, 5000);
}).fail(function(jqXhr, error) {
var alert = $('#alertFailure');
var text = $("#alertFailureText");
text.text(error.ErrorMessage);
alert.show();
});
}
function FiletoBase64(input, imgName, Base64TextName) {
var preview = document.getElementById(imgName);
var file = input.files[0];
var reader = new FileReader();
reader.addEventListener("load",
function() {
preview.src = reader.result;
document.getElementById(Base64TextName).value = reader.result;
},
false);
if (file) {
reader.readAsDataURL(file);
}
}
</script>

How to use a single AngularJS directive to display error messages for multiple file inputs

I have multiple file inputs in a single page
as given below
<input data-file="cancelledCheque" name="cancelledCheque" type="file"
class="fileUpload" ng-file-select="onFileSelect($files)" accept=".jpg,.jpeg">
My directive is as below
App.directive("ngFileSelect", function () {
return {
link: function ($scope, el) {
el.on('click', function () {
this.value = '';
});
el.bind("change", function (e) {
$scope.file = (e.srcElement || e.target).files[0];
var allowed = ["jpeg", "jpg"];
var found = false;
var img;
$scope.filevaliderror = false;
img = new Image();
allowed.forEach(function (extension) {
if ($scope.file.type.match('' + extension)) {
found = true;
$('.filevaliderror').css('display', 'none');
}
});
if (!found) {
//alert('file type should be .jpeg, .jpg');
$('.filevaliderror').css('display', 'block');
return;
}
img.onload = function () {
//var dimension = $scope.selectedImageOption.split(" ");
//if (dimension[0] == this.width && dimension[2] == this.height) {
allowed.forEach(function (extension) {
if ($scope.file.type.match('' + extension)) {
found = true;
$('.filevaliderror').css('display', 'none');
}
});
if (found) {
if ($scope.file.size <= 4194304) {
$scope.getFile();
$('.filevaliderror').css('display', 'none');
} else {
//alert('file size should not be greater then 4 Mb.');
//$scope.file.value = "";
//$scope.filevaliderror = true;
$('.filevaliderror').css('display', 'block');
}
} else {
//alert('file type should be .jpeg, .jpg,');
//$scope.filevaliderror = true;
$('.filevaliderror').css('display', 'block');
}
//} else {
// alert('selected image dimension is not equal to size drop down.');
//}
};
img.src = URL.createObjectURL($scope.file);
});
}
};
Now the Problem I am facing is when a single upload is getting the error displayed all the inputs are displaying the error since I am using a class
so what should I do to display error uniquely using same directive
Given below is my span
<span class="filevaliderror" style="padding-top:4px; color:#af0e0e">Upload a valid File</span>
It is hard to manipulate the error element since it is outside of your directive's markup. Have your directive wrap both the file input and error block like this:
<div ng-select-file>
<input type="file"/>
<span ng-show="error">{{error}}"</span>
</div>
and then show or hide the error by changing the error property of the scope:
link: function ($scope, el) {
el.find('input').bind('change', function (e) {
var file = (e.srcElement || e.target).files[0];
$scope.error = '';
// validate input and show errors...
var isValid = false;
if (!isValid) {
$timeout(function(){
$scope.error = 'Wrong file type';
});
}
});
}
This is the angular way of doing this.
Here the working basic sample: https://jsfiddle.net/aleckravets/awuLh6gu/
<span class="filevaliderror" style="padding-top:4px;
color:#af0e0e" ng-if="submitted &&
form.cancelledCheque.$error.cancelledCheque">Upload a valid File Error</span>
<span ng-if="submitted && form.cancelledCheque.$error.required">required</span>
You could change something to above so that the error shown only to a particular field.

Modified code is not correct for the getvalue and setvalue

My code was working fine but they wanted to change my code....
they wanted to attach setValue and getValue added directly to
footballPanel instead of sports grid,
but after adding it the code is not working fine...
can you tell me why its not working....
providing my modified code below...
the UI action here I am performing is there are two radio buttons,
when I click each radio button two different grids open
in one of the grid we add value, when i switch back to another radio
button the values in another grid disappears but it should not
disappear...
after I modified the code the values disappear, can you tell me why?
Only part of modified code here
else {
this.setDisabled(true);
this.addCls("sports-item-disabled");
if (sportsGrid.store.getCount() > 0) {
var footballPanel = sportsGrid.up('panel');
footballPanel.holdValue = footballPanel.getValue();
footballPanel.setValue();
sportsGrid.addCls("sports-item-disabled");
}
}
Whole modified code:
sportsContainerHandler: function(radioGroup, newValue, oldValue, options) {
var sportsCustomParams = options.sportsCustomParams;
var uiPage = this.up('football-ux-sports-ui-page');
var SportsDefinition = metamodelsHelper.getSportsDefinition(
uiPage, sportsCustomParams.SportsHandlerDefinitionId);
var sportsFieldParam = SportsDefinition.params['sportsMultiFieldName'];
var sportsGrid = uiPage.queryById(sportsFieldParam.defaultValue).grid;
if (newValue[radioGroup.name] == 'sportss') {
this.setDisabled(false);
this.removeCls("sports-item-disabled");
if (sportsGrid.holdValue) {
var footballPanel = sportsGrid.up('panel');
footballPanel.setValue(sportsGrid.holdValue);
}
} else {
this.setDisabled(true);
this.addCls("sports-item-disabled");
**if (sportsGrid.store.getCount() > 0) {
var footballPanel = sportsGrid.up('panel');
footballPanel.holdValue = footballPanel.getValue();
footballPanel.setValue();
sportsGrid.addCls("sports-item-disabled");
}**
}
},
Working code without modification
sportsContainerHandler: function(radioGroup, newValue, oldValue, options) {
var sportsCustomParams = options.sportsCustomParams;
var uiPage = this.up('football-ux-sports-ui-page');
var SportsDefinition = metamodelsHelper.getSportsDefinition(
uiPage, sportsCustomParams.SportsHandlerDefinitionId);
var sportsFieldParam = SportsDefinition.params['sportsMultiFieldName'];
var sportsGrid = uiPage.queryById(sportsFieldParam.defaultValue).grid;
if (newValue[radioGroup.name] == 'sportss') {
this.setDisabled(false);
this.removeCls("sports-item-disabled");
if (sportsGrid.holdValue) {
var footballPanel = sportsGrid.up('panel');
footballPanel.setValue(sportsGrid.holdValue);
}
} else {
this.setDisabled(true);
this.addCls("sports-item-disabled");
if (sportsGrid.store.getCount() > 0) {
sportsGrid.holdValue = sportsGrid.store.data.items;
sportsGrid.store.loadData([]);
sportsGrid.addCls("sports-item-disabled");
}
}
},
getValue() is not a method of ExtJS Panel class.
The change in your code, from sportsGrid (Ext.grid.Panel) to footbalPanel (Ext.panel.Panel) won't work, because they are from different classes and therefore have different properties and methods.
If you want this code to work, you'll need to implement getValue() and setValue(). For example, something like:
On FootballPanel class:
getValue: function () {
return this.down('grid').store.data.items;
},
setValue: function (newValue) {
if (!newValue)
newValue = new Array();
this.down('grid').store.loadData(newValue);
},
And use your modified code:
sportsContainerHandler: function(radioGroup, newValue, oldValue, options) {
var sportsCustomParams = options.sportsCustomParams;
var uiPage = this.up('football-ux-sports-ui-page');
var SportsDefinition = metamodelsHelper.getSportsDefinition(
uiPage, sportsCustomParams.SportsHandlerDefinitionId);
var sportsFieldParam = SportsDefinition.params['sportsMultiFieldName'];
var sportsGrid = uiPage.queryById(sportsFieldParam.defaultValue).grid;
if (newValue[radioGroup.name] == 'sportss') {
this.setDisabled(false);
this.removeCls("sports-item-disabled");
if (sportsGrid.holdValue) {
var footballPanel = sportsGrid.up('panel');
footballPanel.setValue(sportsGrid.holdValue);
}
} else {
this.setDisabled(true);
this.addCls("sports-item-disabled");
if (sportsGrid.store.getCount() > 0) {
var footballPanel = sportsGrid.up('panel');
footballPanel.holdValue = footballPanel.getValue();
footballPanel.setValue([]);
sportsGrid.addCls("sports-item-disabled");
}
}
},

HTML File Input Angularjs Select same File only fires ones

I've made a Angular directive to warp the a file upload input.
directive('ngFile', function () {
return {
link: function (scope, element, attrs) {
var button = element.find('button[data-fileInputButton]');
var inputElement = element.find('input[type="file"]');
var updateModel = function (evt) {
scope.$apply(function () {
scope.files = evt.target.files;
if (scope.startUpload) {
scope.startUpload();
}
evtl.target.files = [];
});
}
inputElement.bind('change', updateModel);
button.click(function () {
var input = element.find('input[type="file"]');
input.click();
});
}
}
});
When I click and select a file, everything is OK. However, when I select the file again, the event is not fired. It is only fired when I select another file. Why is this happening?
The change is listening to the value and not to the files.
you need to do:
evt.target.value = "";
Good luck :)

AngularJS Masonry for Dynamically changing heights

I have divs that expand and contract when clicked on. The Masonry library has worked great for initializing the page. The problem I am experiencing is that with the absolute positioning in place from Masonry and the directive below, when divs expand they overlap with the divs below. I need to have the divs below the expanding div move down to deal with the expansion.
My sources are:
http://masonry.desandro.com/
and
https://github.com/passy/angular-masonry/blob/master/src/angular-masonry.js
/*!
* angular-masonry <%= pkg.version %>
* Pascal Hartig, weluse GmbH, http://weluse.de/
* License: MIT
*/
(function () {
'use strict';
angular.module('wu.masonry', [])
.controller('MasonryCtrl', function controller($scope, $element, $timeout) {
var bricks = {};
var schedule = [];
var destroyed = false;
var self = this;
var timeout = null;
this.preserveOrder = false;
this.loadImages = true;
this.scheduleMasonryOnce = function scheduleMasonryOnce() {
var args = arguments;
var found = schedule.filter(function filterFn(item) {
return item[0] === args[0];
}).length > 0;
if (!found) {
this.scheduleMasonry.apply(null, arguments);
}
};
// Make sure it's only executed once within a reasonable time-frame in
// case multiple elements are removed or added at once.
this.scheduleMasonry = function scheduleMasonry() {
if (timeout) {
$timeout.cancel(timeout);
}
schedule.push([].slice.call(arguments));
timeout = $timeout(function runMasonry() {
if (destroyed) {
return;
}
schedule.forEach(function scheduleForEach(args) {
$element.masonry.apply($element, args);
});
schedule = [];
}, 30);
};
function defaultLoaded($element) {
$element.addClass('loaded');
}
this.appendBrick = function appendBrick(element, id) {
if (destroyed) {
return;
}
function _append() {
if (Object.keys(bricks).length === 0) {
$element.masonry('resize');
}
if (bricks[id] === undefined) {
// Keep track of added elements.
bricks[id] = true;
defaultLoaded(element);
$element.masonry('appended', element, true);
}
}
function _layout() {
// I wanted to make this dynamic but ran into huuuge memory leaks
// that I couldn't fix. If you know how to dynamically add a
// callback so one could say <masonry loaded="callback($element)">
// please submit a pull request!
self.scheduleMasonryOnce('layout');
}
if (!self.loadImages){
_append();
_layout();
} else if (self.preserveOrder) {
_append();
element.imagesLoaded(_layout);
} else {
element.imagesLoaded(function imagesLoaded() {
_append();
_layout();
});
}
};
this.removeBrick = function removeBrick(id, element) {
if (destroyed) {
return;
}
delete bricks[id];
$element.masonry('remove', element);
this.scheduleMasonryOnce('layout');
};
this.destroy = function destroy() {
destroyed = true;
if ($element.data('masonry')) {
// Gently uninitialize if still present
$element.masonry('destroy');
}
$scope.$emit('masonry.destroyed');
bricks = [];
};
this.reload = function reload() {
$element.masonry();
$scope.$emit('masonry.reloaded');
};
}).directive('masonry', function masonryDirective() {
return {
restrict: 'AE',
controller: 'MasonryCtrl',
link: {
pre: function preLink(scope, element, attrs, ctrl) {
var attrOptions = scope.$eval(attrs.masonry || attrs.masonryOptions);
var options = angular.extend({
itemSelector: attrs.itemSelector || '.masonry-brick',
columnWidth: parseInt(attrs.columnWidth, 10) || attrs.columnWidth
}, attrOptions || {});
element.masonry(options);
var loadImages = scope.$eval(attrs.loadImages);
ctrl.loadImages = loadImages !== false;
var preserveOrder = scope.$eval(attrs.preserveOrder);
ctrl.preserveOrder = (preserveOrder !== false && attrs.preserveOrder !== undefined);
scope.$emit('masonry.created', element);
scope.$on('$destroy', ctrl.destroy);
}
}
};
}).directive('masonryBrick', function masonryBrickDirective() {
return {
restrict: 'AC',
require: '^masonry',
scope: true,
link: {
pre: function preLink(scope, element, attrs, ctrl) {
var id = scope.$id, index;
ctrl.appendBrick(element, id);
element.on('$destroy', function () {
ctrl.removeBrick(id, element);
});
scope.$on('masonry.reload', function () {
ctrl.scheduleMasonryOnce('reloadItems');
ctrl.scheduleMasonryOnce('layout');
});
scope.$watch('$index', function () {
if (index !== undefined && index !== scope.$index) {
ctrl.scheduleMasonryOnce('reloadItems');
ctrl.scheduleMasonryOnce('layout');
}
index = scope.$index;
});
}
}
};
});
}());
Like with many non-Angular libraries, it appears the answer lies in wrapping the library in an Angular directive.
I haven't tried it out but it appears that is what this person did
You can use angular's $emit, $broadcast, and $on functionality.
Inside your masonry directive link function:
scope.$on('$resizeMasonry', ctrl.scheduleMasonryOnce('layout'));
Inside your masonryBrick directive link function or any other child element:
scope.$emit('$resizeMasonry');
Use $emit to send an event up the scope tree and $broadcast to send an event down the scope tree.

Categories

Resources