Dropzone becomes inactive when used in AngularJS ng-view - angularjs

I have a controller that displays images via a template that is passed through ng-view and runs smoothly. I also have dropzone up and running and working smoothly. However, as soon as I add dropzone to the template the dropzone is no longer active. It displays (the zone isn't clickable unless I manually add dz-clickable, but still does nothing).
I could add the dropzone in a ng-include above the area and have it hidden when the template is looking elsewhere but have heard that ng-include uses more processor than ng-view so would prefer to keep it all together.
I have seen that there is a dropzone angularjs directive but have not managed to merge it successfully with my controller that gets placed into the ng-view or if that would even be successful?
Here is the directive:
(function(){
angular.module('dropZone', [])
.directive('dropZone', function() {
return function(scope, element, attrs) {
element.dropzone({
url: "/upload",
maxFilesize: 100,
paramName: "uploadfile",
maxThumbnailFilesize: 5,
init: function() {
scope.files.push({file: 'added'}); // here works
this.on('success', function(file, json) {
});
this.on('addedfile', function(file) {
scope.$apply(function(){
alert(file);
scope.files.push({file: 'added'});
});
});
this.on('drop', function(file) {
alert('file');
});
}
});
}
});
}());
and here is my current controller:
(function() {
'use strict';
angular
.module('app')
.controller('CustomController', CustomController);
CustomController.$inject = ['api'];
function CustomController(api) {
var vm = this;
api.getDesigns()
.then(function(data) {
vm.designs = data;
});
}
}());

Found my own answer. Rather than adding the dropzone hard coded into the template I just programmatically added the dropzone within the controller scope function using :
var myDropzone = new Dropzone("div#myId", { url: "/file/post"});

Related

Custom directive for preloading background image not working AngularJS

I am working on a custom directive to preload images while the state (with ui-router is changing) so that both data and content are resolved before navigating to the new state.
I have created a Pen here: https://codepen.io/wons88/pen/NgbNvO to show my basic implementation with the bgSrc directive:
app.directive('bgSrc', ['preloadService', function (preloadService) {
return function (scope, element, attrs) {
element.hide();
preloadService(attrs.bgSrc).then(function () {
console.log(element.css);
element.css({
"background-image": "url('" + attrs.bgSrc + "')"
});
element.fadeIn();
});
}
}]);
and the preloadService:
app.factory('preloadService', ['$q', '$rootScope', function ($q, $rootScope) {
return function (url) {
var deffered = $q.defer(),
image = new Image();
image.src = url;
if (image.complete) {
$rootScope.loading = false;
deffered.resolve();
} else {
$rootScope.loading = true;
image.addEventListener('load',
function () {
deffered.resolve();
$rootScope.loading = false;
});
image.addEventListener('error',
function () {
deffered.reject();
$rootScope.loading = true;
});
}
return deffered.promise;
};
}]);
And the HTML:
<div bg-src="https://images5.alphacoders.com/446/thumb-1920-446028.jpg">Background img should show up...</div>
EDIT:
The problem is that the image is never shown even if it is loaded (as shown in the network tab in chrome dev tools). If I make it statically applying style (or class) the image is shown no problem, just loads slower... hence trying to apply the directive.
I know there is something wrong happening in the bgSrc directive but I am unable to pinpoint it. Any help on the matter would be much appreciated :)
element.hide is not a function
You are calling
element.hide();
in your link function, but jQlite does not have a hide() method. Since you did not include jQuery in your Codepen, it's failing on that line.
https://docs.angularjs.org/api/ng/function/angular.element
Instead, use css
element.css('visibility', 'invisible');
Or add jQuery

Angular - How to show modal reject reason in table?

I have small problem to solve.
I have modal controller rejectIssueModalCtrl.js
(function () {
'use strict';
function rejectIssueModalCtrl($modalInstance, issue, $rootScope) {
var self = this;
self.cancel = function () {
$modalInstance.dismiss('cancel');
};
self.reject = function ($rootScope) {
$modalInstance.close(self.reason);
console.log(self.reason);
};
$rootScope.reasono = self.reason;
}
rejectIssueModalCtrl.$inject = ['$modalInstance', 'issue', '$rootScope'];
angular
.module('app')
.controller('rejectIssueModalCtrl', rejectIssueModalCtrl);
})();
When I click the button I can open this modal and write a reason. I want to show this reject reason in table in other controller.
Here's my code from other controller issueDetailsCtrl.js
$scope.reasonoo = $rootScope.reasono;
function rejectIssue() {
var rejectModal = $modal.open({
templateUrl: '/App/Issue/rejectIssueModal',
controller: 'rejectIssueModalCtrl',
controllerAs: 'rejectModal',
size: 'lg',
resolve: {
issue: self.issueData
}
});
rejectModal.result.then(function (reason) {
issueSvc
.rejectIssue(self.issueData.id, reason)
.then(function (issueStatus) {
changeIssueStatus(issueStatus.code);
getIssue();
}, requestFailed);
});
};
and html code
<div>
<span class="right" ng-bind="$root.reasono"></span>
</div>
As you can see I tried to use $rootScope. I can console.log the reason but I cant make it to show in this html. Any help?
We're missing some context, but I believe this is your problem:
self.reject = function ($rootScope) {
$modalInstance.close(self.reason);
console.log(self.reason);
};
$rootScope.reasono = self.reason;
Assuming self.reason is bound to the input in your modal, it won't be defined outside of the reject callback - that's the nature of async. You're able to log to console because you're doing so within the callback.
Define $rootScope.reasono inside of the callback like so:
self.reject = function () {
$modalInstance.close(self.reason);
console.log(self.reason);
$rootScope.reasono = self.reason;
};
Edited to show that $rootScope should be removed as a named parameter in the reject function definition.
Using root scope is not recommended. For this reason it is recommended to create a service for intercommuncation with variable to store reject reason, then inject this service for each controller - that way you will be able to read/write reason from different controllers.

AngularStrap Modal Usage

I am currently using AngularStrap v2.3.1 and AngularJS v1.4.5.
I've been having some trouble getting AngularStrap's modals to work. It's most likely a misunderstanding of how it should work, as the documentation isn't too helpful. I am using the controllerAs syntax everywhere in my app.
From what I understood, I could create an object in the controller as such:
vm.editModal = {
contentTemplate: '/templates/edit.html',
backdrop: 'static',
show: false
};
And then in my view, I would use the bs-modal with the modal property:
<a href="" bs-modal="ctrl.editModal">
However, all I get is a blank modal. It actually doesn't seem to be taking any of the properties from editModal. So it led me to believe that doing it that way only uses the title and content attributes. So it's for a basic modal?
I also tried using the $modal service, which I did inject into the controller. And then tried:
vm.editModal = $modal({
show: false,
contentTemplate: '/templates/edit.html',
backdrop: 'static',
});
And I used the same HTML:
<a href="" bs-modal="ctrl.editModal">
However, in this case, I got a bunch of errors in the console and it didn't work either. Some errors;
[ng:cpws] Can't copy! Making copies of Window or Scope instances is not supported.
[$rootScope:infdig] 10 $digest() iterations reached.
As soon as I can get this working, I'd then like to try resolving data before the modal loads. But I haven't even gotten that far yet.
If someone could point me in the right direction, it'd be much appreciated.
Thanks!
mgcrea has a great example using a service to exchange information with the modal
.service('$confirm', function($modal, $rootScope, $q) {
var scope = $rootScope.$new();
var deferred;
scope.title = 'confirm';
scope.content = 'Confirm deletion?';
scope.answer = function(res) {
deferred.resolve(res);
confirm.hide();
}
var confirm = $modal({template: 'confirm.tpl.html', scope: scope, show: false});
var parentShow = confirm.show;
confirm.show = function() {
deferred = $q.defer();
parentShow();
return deferred.promise;
}
return confirm;
})
.controller('ModalDemoCtrl', function($scope, $confirm) {
$scope.delete = function() {
$confirm.show().then(function(res) {
console.warn('answered', res)
})
};
Here -> http://plnkr.co/edit/KnRMGw5Avz2MW3TnzuVT
Hope this helps

Getting button to fire using Controller as vm syntax in AngularJS 1.3

I've got the code below that shows that I can use $scope.interestToggle = syntax but not vm.interestToggle = syntax to assign a listener to a button click. I'm trying to avoid using $scope. Is there a correct or better way to put a listener in a controller than hanging it off $scope?
(function () {
"use strict";
angular
.module("svCodeCamp")
.controller( "SessionListCtrl",
['$scope',"sessionResource",
SessionListCtrl]);
function SessionListCtrl($scope,sessionResource) {
var vm = this;
// WORKS
$scope.interestToggle = function(item) {
debugger;
}
// DOES NOT WORK
vm.interestToggle = function(item) {
debugger;
}
//<td>
//<button ng:click="interestToggle()">Add</button>
//</td>
Global controllers aren't (completely) supported in 1.3.
you should be using:
angular.module("svCodeCamp").controller("SessionListCtrl", ['$scope',"sessionResource", function() {
// controller content
]);
or use this to reenable global controllers:
angular.module('svCodeCamp').config(['$controllerProvider', function($controllerProvider) {
// this option might be handy for migrating old apps, but please don't use it
// in new ones!
$controllerProvider.allowGlobals();
}]);

AngularJs event to call after content is loaded

I have a function which I want to call after page content is loaded. I read about $viewContentLoaded and it doesn't work for me. I am looking for something like
document.addEventListener('DOMContentLoaded', function () {
//Content goes here
}, false);
Above call doesn't work for me in AngularJs controller.
According to documentation of $viewContentLoaded, it supposed to work
Emitted every time the ngView content is reloaded.
$viewContentLoaded event is emitted that means to receive this event you need a parent controller like
<div ng-controller="MainCtrl">
<div ng-view></div>
</div>
From MainCtrl you can listen the event
$scope.$on('$viewContentLoaded', function(){
//Here your view content is fully loaded !!
});
Check the Demo
Angular < 1.6.X
angular.element(document).ready(function () {
console.log('page loading completed');
});
Angular >= 1.6.X
angular.element(function () {
console.log('page loading completed');
});
fixed - 2015.06.09
Use a directive and the angular element ready method like so:
js
.directive( 'elemReady', function( $parse ) {
return {
restrict: 'A',
link: function( $scope, elem, attrs ) {
elem.ready(function(){
$scope.$apply(function(){
var func = $parse(attrs.elemReady);
func($scope);
})
})
}
}
})
html
<div elem-ready="someMethod()"></div>
or for those using controller-as syntax...
<div elem-ready="vm.someMethod()"></div>
The benefit of this is that you can be as broad or granular w/ your UI as you like and you are removing DOM logic from your controllers. I would argue this is the recommended Angular way.
You may need to prioritize this directive in case you have other directives operating on the same node.
You can directly call it by adding {{YourFunction()}} after HTML element.
Here is a Plunker Link.
I had to implement this logic while handling with google charts. what i did was that at the end of my html inside controller definition i added.
<body>
-- some html here --
--and at the end or where ever you want --
<div ng-init="FunCall()"></div>
</body>
and in that function simply call your logic.
$scope.FunCall = function () {
alert("Called");
}
var myM = angular.module('data-module');
myM.directive('myDirect',['$document', function( $document ){
function link( scope , element , attrs ){
element.ready( function(){
} );
scope.$on( '$viewContentLoaded' , function(){
console.log(" ===> Called on View Load ") ;
} );
}
return {
link: link
};
}] );
Above method worked for me
you can call javascript version of onload event in angular js. this ng-load event can be applied to any dom element like div, span, body, iframe, img etc. following is the link to add ng-load in your existing project.
download ng-load for angular js
Following is example for iframe, once it is loaded testCallbackFunction will be called in controller
EXAMPLE
JS
// include the `ngLoad` module
var app = angular.module('myApp', ['ngLoad']);
app.controller('myCtrl', function($scope) {
$scope.testCallbackFunction = function() {
//TODO : Things to do once Element is loaded
};
});
HTML
<div ng-app='myApp' ng-controller='myCtrl'>
<iframe src="test.html" ng-load callback="testCallbackFunction()">
</div>
If you're getting a $digest already in progress error, this might help:
return {
restrict: 'A',
link: function( $scope, elem, attrs ) {
elem.ready(function(){
if(!$scope.$$phase) {
$scope.$apply(function(){
var func = $parse(attrs.elemReady);
func($scope);
})
}
else {
var func = $parse(attrs.elemReady);
func($scope);
}
})
}
}
I was using {{myFunction()}} in the template but then found another way here using $timeout inside the controller. Thought I'd share it, works great for me.
angular.module('myApp').controller('myCtrl', ['$timeout',
function($timeout) {
var self = this;
self.controllerFunction = function () { alert('controller function');}
$timeout(function () {
var vanillaFunction = function () { alert('vanilla function'); }();
self.controllerFunction();
});
}]);
Running after the page load should partially be satisfied by setting an event listener to the window load event
window.addEventListener("load",function()...)
Inside the module.run(function()...) of angular you will have all access to the module structure and dependencies.
You can broadcast and emit events for communications bridges.
For example:
module set onload event and build logic
module broadcast event to controllers when logic required it
controllers will listen and execute their own logic based on module onload processes.
If you want certain element to completely loaded, Use ng-init on that element .
e.g. <div class="modal fade" id="modalFacultyInfo" role="dialog" ng-init="initModalFacultyInfo()"> ..</div>
the initModalFacultyInfo() function should exist in the controller.
I found that if you have nested views - $viewContentLoaded gets triggered for every of the nested views. I've created this workaround to find the final $viewContentLoaded. Seems to work alright for setting $window.prerenderReady as required by Prerender (goes into .run() in the main app.js):
// Trigger $window.prerenderReady once page is stable
// Note that since we have nested views - $viewContentLoaded is fired multiple
// times and we need to go around this problem
var viewContentLoads = 0;
var checkReady = function(previousContentLoads) {
var currentContentLoads = Number(viewContentLoads) + 0; // Create a local copy of the number of loads
if (previousContentLoads === currentContentLoads) { // Check if we are in a steady state
$window.prerenderReady = true; // Raise the flag saying we are ready
} else {
if ($window.prerenderReady || currentContentLoads > 20) return; // Runaway check
$timeout(function() {checkReady(currentContentLoads);}, 100); // Wait 100ms and recheck
}
};
$rootScope.$on('$stateChangeSuccess', function() {
checkReady(-1); // Changed the state - ready to listen for end of render
});
$rootScope.$on('$viewContentLoaded', function() {
viewContentLoads ++;
});
var myTestApp = angular.module("myTestApp", []);
myTestApp.controller("myTestController", function($scope, $window) {
$window.onload = function() {
alert("is called on page load.");
};
});
The solution that work for me is the following
app.directive('onFinishRender', ['$timeout', '$parse', function ($timeout, $parse) {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
$timeout(function () {
scope.$emit('ngRepeatFinished');
if (!!attr.onFinishRender) {
$parse(attr.onFinishRender)(scope);
}
});
}
if (!!attr.onStartRender) {
if (scope.$first === true) {
$timeout(function () {
scope.$emit('ngRepeatStarted');
if (!!attr.onStartRender) {
$parse(attr.onStartRender)(scope);
}
});
}
}
}
}
}]);
Controller code is the following
$scope.crearTooltip = function () {
$('[data-toggle="popover"]').popover();
}
Html code is the following
<tr ng-repeat="item in $data" on-finish-render="crearTooltip()">
I use setInterval to wait for the content loaded. I hope this can help you to solve that problem.
var $audio = $('#audio');
var src = $audio.attr('src');
var a;
a = window.setInterval(function(){
src = $audio.attr('src');
if(src != undefined){
window.clearInterval(a);
$('audio').mediaelementplayer({
audioWidth: '100%'
});
}
}, 0);

Resources