losing scope in controller via factory - angularjs

I am having the following problem where I lose the scope variable (movie) in the controller (using a factory method). If I set the variable outside the function, things work (the LOOL movie). Can someone help please ?
film.getMovie().then(function (response) {
$scope.movie = response;
console.log(response);
}, function (error) {
console.error(error);
});
Here is the plnkr of the problem.
Thanks a lot.

http://plnkr.co/edit/OlQaLXO1GMvMMDJnaQul?p=preview
Use a watch in the directive to know when the value is changed
app.directive('info', function () {
return {
template: '<div></div>',
scope: {
film: '='
},
restrict: 'E',
link: function link(scope, element, attrs) {
scope.$watch('film',function(){
console.log("Scope: " , scope);
console.log("Film:", scope.film); // GRRRRRR
})
}
};
});

Related

Call function in controller with $http.get

When i run this i get no value at all, just endless looping errors. (Error: [$rootScope:infdig])
My html:
{{getName(5)}}
This is my function:
$scope.getName = function(id) {
$http.get('get.php?id='+id).then(function(response) {
return response.data;
});
}
When i call get.php?id=5 i get a normal answer like: "Jake Something"
When i call $scope.getName(5) in my controller i get the right value, no errors.
Is there a way to fix this or any other way to get the right values?
Fixed it by using directive:
myApp.directive('getCustomer', function($http) {
return {
restrict : 'E',
scope: {
customerid: '='
},
template: "{{data}}",
link: function(scope, elem, attr) {
var url = 'get.php?id='+scope.customerid;
$http.get(url).then(function(response) {
scope.data = response.data;
});
}
};
});
in html:
<get-customer customerid="5"></get-customer>
Outputs:
Jake Something

Reinitialise directive on change of attribute

I have two directives, calling 2nd directive from 1st directive.
This is my 1st directive
var initializeWidget = function ($compile, $timeout, $rootScope) {
return {
restrict: 'EA',
scope: {
maxImages: '#',
},
link: function (scope, element, attrs) {
if (!scope.cloudinaryFolder) {
throw 'folder value is missing in image uploader directive';
}
if (!scope.cloudinaryTags) {
throw 'tags value is missing in image uploader directive';
}
//1
attrs.$observe('maxImages', function (newMaxImages) {
console.log('varun==' + newMaxImages);
$timeout(function () {
angular.element(document.body).append($compile('<div class="sp-upload-widget" sp-upload-widget up-max-images="' + scope.maxImages + '"></div>')(scope));
scope.$apply();
}, 10);
});
}
};
};
I am calling my 2nd directive usixng angular.element used in above code.
Below is my 2nd directive:
var spUploadWidget = function ($q, Cloudinary, ENV) {
var templateUrl;
if ('dev' === ENV.name) {
templateUrl = '/seller/modules/uploadWidget/views/upload.html';
}
else if ('prod' === ENV.name) {
templateUrl = './views/upload.html';
}
return {
restrict: 'AE',
scope: {},
bindToController: {
maxImages: '=?upMaxImages',
},
replace: false,
controller: 'uploadWidgetController',
controllerAs: 'up',
templateUrl: templateUrl,
};
};
now in my controller when I am checking value of maxImages then it is giving the updated value but when I am using this variable to call API then it is holding the older value. Here is my controller
console.log('up===' + self.maxImages);
self.openUploader = function () {
self.closeModal();
ABC.UploaderInit( self.maxImages);
};
So when I change the value of maxImages in my directive
<div initialize-widget max-images="maxImages"></div>
It should give the updated value to my ABC.UploaderInit function
Found a solution for my problem,
I was getting this problem because I was calling 2nd directive whenever attribute of 1st directive was changing so I was creating multiple instances of my directive.
So now to handle this I am destroying the older instance of 2nd directive before I call the 2nd directive.
$rootScope.$on('destroySpUploadWidget', function (event, args) {
if (args.modalId === ctrl.modalId) {
scope.$destroy();
element.remove();
}

Call method in controller from directive

HTML :
<div id="idOfDiv" ng-show="ngShowName">
Hello
</div>
I would like to call the function which is declared in my controller from my directive.
How can I do this? I don't receive an error when I call the function but nothing appears.
This is my directive and controller :
var d3DemoApp = angular.module('d3DemoApp', []);
d3DemoApp.controller('mainController', function AppCtrl ($scope,$http, dataService,userService,meanService,multipartForm) {
$scope.testFunc = function(){
$scope.ngShowName = true;
}
});
d3DemoApp.directive('directiveName', [function($scope) {
return {
restrict: 'EA',
transclude: true,
scope: {
testFunc : '&'
},
link: function(scope) {
node.on("click", click);
function click(d) {
scope.$apply(function () {
scope.testFunc();
});
}
};
}]);
You shouldn't really be using controllers and directives. Angularjs is meant to be used as more of a component(directive) based structure and controllers are more page centric. However if you are going to be doing it this way, there are two ways you can go about it.
First Accessing $parent:
If your directive is inside the controllers scope you can access it using scope.$parent.mainController.testFunc();
Second (Preferred Way):
Create a service factory and store your function in there.
d3DemoApp.factory('clickFactory', [..., function(...) {
var service = {}
service.testFunc = function(...) {
//do something
}
return service;
}]);
d3DemoApp.directive('directiveName', ['clickFactory', function(clickFactory) {
return {
restrict: 'EA',
transclude: true,
link: function(scope, elem) {
elem.on("click", click);
function click(d) {
scope.$apply(function () {
clickFactory.testFunc();
});
}
};
}]);
Just a tip, any time you are using a directive you don't need to add $scope to the top of it. scope and scope.$parent is all you really need, you will always have the scope context. Also if you declare scope :{} in your directive you isolate the scope from the rest of the scope, which is fine but if your just starting out could make things quite a bit more difficult for you.
In your link function you are using node, which doesn't exist. Instead you must use element which is the second parameter to link.
link: function(scope, element) {
element.on("click", click);
function click(d) {
scope.$apply(function() {
scope.testFunc();
});
}

Passing ng-click/ng-submit promise to directive

Basically, I created a directive that passes a promise to the link function from ng-click and and detects when the promise is done so that I can attach a class to it.
Example:
.directive('myDirective', function($parse) {
return {
restrict: 'A',
scope: {
ng-click: '&'
},
link: function(scope) {
var d = $parse(scope.ngClick);
element.on('click', function(event) {
d().then(function() {
element.addClass(attrs.myDirective);
});
});
}
};
});
<element ng-click="promise();" my-directive="class"></element>
//controller function
$scope.promise = function() {
return promise().then(function() {});
}
It is doing what I want except that the controller function is getting called three times. I would really like to just use require: '^ngClick' here but since the ngClick directive does not have any controllers, I can't do that. Can anyone point me in the right direction? Thanks!
Added event.preventDefault() to the event.on('click') function in the link of my directive:
element.on('click', function(event) {
event.preventDefault();
d().then(function() {
element.addClass(attrs.myDirective);
});
});

Angularjs avoid $emit and share a variable across directives

I have a situtation where in i want to avoid using $emit to share a scope variable and instead share some property using a underlying service, the problem is that the property value gets set on return of a promise response in directive 1 and by the time that property value is set in service through directive 1, directive 2 is already loaded and hence the property comes as undefined in directive 2.
Any ideas?
With the provided information, thought of writing this code fragment. Hope this will give you some insights to find the best answer.
angular.module('myApp').service('SomeService', function($http) {
this.readData = function(dataUrl) {
// read data;
return $http.get(dataUrl)
.then(function(res) {
return res.data;
}, function(res) {
return res;
}
}
return this;
});
angular.module('myApp').controller('MyController', function($scope, SomeService) {
$scope.readData = function(url) {
SomeService.readData(url)
.then(function(res) {
$scope.data = res;
}, function(res) {
// Display error
}
}
}
angular.module('myApp').directory('myDirectory1', function() {
return {
restrict: 'A',
link: function(scope, elm, attrs) {
scope.data = scope.readData(url);
}
}
});
angular.module('myApp').directory('myDirectory2', function() {
return {
restrict: 'A',
scope: {
data : '#'
},
link: function(scope, elm, attrs) {
scope.$watch('data', function(newVal) {
// Do some stuffs
});
}
}
});
Perhaps extract the functionality that delivers the promise from your directive1 to the service, and in both directives use
.then(function(data){ ... } )

Resources