Call function in controller with $http.get - angularjs

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

Related

$scope.$watch doesn't update after service call in directive

I have a directive which loads a image data template.
The problem is that It doesn't update the image date after the service which retrieve the img information is called.
This is my code:
Controller method:
$scope.watchImage = function(file_id){
FileService.getFile(file_id)
.then(
function(data){
if(data.file){
$scope.img = data.file;
console.log('Service called');
}
}
);
}
Directive:
app.directive('imageDetails', function() {
return {
scope: {
img: '='
},
restrict: 'E',
link: function($scope, element, attrs){
$scope.$watch(function() {
return $scope.img;
}, function() {
console.log($scope.img);
});
},
template: 'IMG: {img}'
};
});
HTML:
<div class="ui container">
<h2 class="ui dividing header">Images</h2>
</div>
<div ng-view></div>
<image-details img="img"></image-details>
</div>
Log result:
undefined
Service called
Any idea how to solve it ?
Thanks!
First of all, thank you to everyone for your replies. All of them help me in the solution.
Finally this is my working code.
Directive:
app.directive('imageDetails', function() {
return {
scope: {
img: '='
},
restrict: 'E',
template: 'IMG: {{img}}'
};
});
And I added the directive to my template (I was adding it outside ngview).
you have some mistake in template and in link function.
var app = angular.module('myApp', []);
app.controller('mainCtrl', function ($scope) {
$scope.img = {id: 1, title: "avatar.jpeg", slug: "avatar.jpeg", filesize: 24875, created_at: "2016-03-10 11:44:59"};
})
app.directive('imageDetails', function() {
return {
scope: {
img: '='
},
restrict: 'E',
link: function(scope, element, attrs){
scope.$evalAsync(function() {
return scope.img;
});
},
template: 'IMG: {{img}}'
};
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="myApp" ng-controller="mainCtrl">
<image-details img="img"></image-details>
</div>
I think your directive should be Like :
app.directive('imageDetails', function() {
return {
scope: {
img: '='
},
restrict: 'E',
link: function(scope, element, attrs){
scope.$watch('img',function(image) {
return image;
}, function() {
console.log(image);
});
},
template: 'IMG: {img}'
};
});
First of all use a controller instead of link function because you don't need that. Link function is deprecated for simple components like this in angular 1.5.
Then, for using $watch, you need to specify what variable you want to watch, and only after what to do when it's change.
$watch('varToWatch', function(newValue) {...});
That said, if you use a controller instead of the link function, you probably use also a "Controller as" syntax. When you use it, you need to specify the "view name" of the variable you want to watch. For example:
app.directive('imageDetails', function() {
return {
scope: {
img: '='
},
restrict: 'E',
controllerAs: '$ctrl',
controller: function($scope){
$scope.$watch('$ctrl.img', function(newVal) {
console.log(newVal);
// if you want you can assign new value to your variable
// $scope.img = newVal;
});
},
template: 'IMG: {img}'
};
});
Try that and tell me if it's works for you ;)
This is a clear case of when the scope is affected outside the module. For those cases the lifecycle will not do the digest of the scope as you will expect.
You have to manually $digest or $apply when you want to notify your app that the scope have changed inside your directive

losing scope in controller via factory

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
})
}
};
});

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){ ... } )

how to make angular directive accept string or model respectively

I am trying to create an angular directive that will be able to get BOTH model object and a string.
if the directive get a string it just output HTML, but if it's a model the the directive will watch the model for changes and will output data respectively.
I had tried to use the next code:
App.directive('iso2symbol', function () {
return {
restrict: 'E',
replace: true,
link: function ($scope, $element, $attrs) {
var curIsoObj = $scope.$eval($attrs.curIso);
//this is object it may change
if (typeof curIsoObj !== 'undefined') {
console.log('not a text');
$scope.$watch('curIso', function (value) {
console.log(value);
});
}
},
template: '<span>{{currencySymbol}}</span>'
}
}]);
This is not working, I had googled it for long time and I don't find the problem....
here is a link to JSfiddle where I had set a DEMO
Becareful with what you're watching.
according to your watch function you're watching $scope.curIso which really isn't a scope object.
you should be watching
$scope.$watch(function(){return $scope.$eval($attrs.curIso);}, function (value) {
$scope.txt = value;
});
Try this:
App.directive('iso2symbol', function () {
return {
restrict: 'E',
replace: true,
require: 'ngModel',
scope: {
curIso: '='
},
link: function ($scope, $element, $attrs) {
$scope.$observe('curIso', function(newValue, oldValue){
var curIsoObj = newValue;
// Do your test now to see if it's undefined,
// a string, or generic object.
// (the first time it will likely be undefined)
}
},
template: '<span>{{currencySymbol}}</span>'
}
}]);

How to use require option in directives

In documentation I can read next for the require option:
When a directive uses this option, $compile will throw an error
unless the specified controller is found. The ^ prefix means that this
directive searches for the controller on its parents (without the ^
prefix, the directive would look for the controller on just its own
element).
So I try to use it:
<div ng-sparkline></div>
app.directive('ngCity', function() {
return {
controller: function($scope) {}
}
});
app.directive('ngSparkline', function() {
return {
restrict: 'A',
require: '^ngCity',
scope: {},
template: '<div class="sparkline"><h4>Weather </h4></div>',
link: function(scope, iElement, iAttrs) {
// get weather details
}
}
});
But I have an error if my html have not ng-city attribute, so if I need controller of another directive - need to add exactly same attribute in html, but why (<div ng-sparkline ng-city="San Francisco"></div>)? And it looks on another directive's controller with this name (directive!!!) but not at controller with this name, is that true? Thanks. Just want to make it clear
With require you can get the controller of another (cooperating) directive. The controller in Angular is not semantically a function, but an object constructor, i.e. called essentially as var c = new Controller() (this is a simplification for the sake of clarity). Since the controller is an object, it can have properties and methods. By requiring the controller of another directive, you gain access to those properties/methods. Modifying your example to demonstrate:
app.directive('ngCity', function() {
return {
controller: function($scope) {
this.doSomething = function() {
...
};
}
}
});
app.directive('ngSparkline', function() {
return {
restrict: 'A',
require: '^ngCity',
scope: {},
template: '<div class="sparkline"><h4>Weather </h4></div>',
link: function(scope, iElement, iAttrs, ngCityController) {
// use the controller, e.g.
ngCityController.doSomething();
}
}
});
In your case, the city would be a property of the controller of the ngCity directive, exposed as a property. It will be read by the ngSparkline to know for which city the graph is about.
<b> added directives.js</b>
<code>
app.directive('ngSparkline', function () {
return {
restrict: 'A',
require: '^ngCity',
scope: {
ngCity: '#'
},
templateUrl: '/scripts/templates/tpl.html',
controller: ['$scope', '$http', function ($scope, $http) {
var url = "https://api.openweathermap.org/data/2.5/forecast/daily?mode=json&units=imperial&cnt=7&callback=JSON_CALLBACK&q=";
console.log(url + $scope.ngCity);
$scope.showTemp = function () {
$scope.getTemp($scope.ngCity);
};
$scope.getTemp = function (city) {
$http({
method: 'JSONP',
url: url + city
}).success(function(data) {
var weather = [];
angular.forEach(data.list, function(value){
weather.push(value);
});
$scope.weather = weather;
});
}
}],
link: function (scope, iElement, iAttrs, ctrl) {
scope.getTemp(iAttrs.ngCity);
scope.$watch('weather', function (newVal) {
if (newVal) {
var highs = [];
angular.forEach(scope.weather, function (value) {
highs.push(value.temp.max);
});
//chartGraph(iElement, highs, iAttrs);
}
});
}
}
}).directive('ngCity', function () {
return {
controller: function ($scope) {
//console.log("hello");
}
}
});
</code>
<b> and added tpl.htm</b>
<code>
<div class="sparkline">
<input type="text" data-ng-model="ngCity">
<button ng-click="showTemp()" class="btn1">Check {{ngCity}}</button>
<div style="color:#2743EF">{{weather}} ÂșC</div>
<div class="graph"></div>
</div>
</code>

Resources