i have an example Plunker. Why binding onto count: 0 not working ? Here is code from *.js file:
var app = angular.module("MyApp", []);
app.controller("objectCtrl", function($scope, sharingData) { $scope.message = sharingData.message; });
app.controller("primitiveCtrl", function($scope, sharingData) { $scope.count = sharingData.message.count; });
app.controller("watchCtrl", function($scope, sharingData) { $scope.message = {};
$scope.$watch(function() {
return sharingData.message.count; }, function(value) {
$scope.message.count = value; }); });
app.factory('sharingData', function() { return {
count: 0,
message: {
count: 0
} }; });
app.run(function($rootScope, sharingData) { $rootScope.Inc = function() {
sharingData.message.count = ++sharingData.count; }; });
Because the variable is not passed by reference but by value.
In order to achieve that, you are forced to do this:
app.controller("primitiveCtrl", function($scope, sharingData) {
$scope.count = sharingData.message;
});
And:
count from primitiveCtrl: {{count.count}}
http://plnkr.co/edit/h8A8PwGJuhD2imRbEsNM?p=preview
EDIT: the fact is that it's not possible to pass by reference a primitive value in javascript. One thing that might resemble this is the following:
app.controller("primitiveCtrl", function($scope, sharingData) {
$scope.getValue= function(){
return sharingData.message.count;
};
});
And:
count from primitiveCtrl: {{getValue()}}
http://plnkr.co/edit/h8A8PwGJuhD2imRbEsNM?p=preview
Related
I neeed to pass a value from this part of the code in my directive to a controller, but not sure how to achieve that:
if (!scope.multiple) {
scope.model = value;
console.log(scope.model);
return;
}
I get the value in the console.log, I just don't know how to pass it to the controller.
This is the complete directive:
angular.module('quiz.directives')
.directive('fancySelect', function($rootScope, $timeout) {
return {
restrict: 'E',
templateUrl: 'templates/directives/fancySelect.html',
scope: {
title: '#',
model: '=',
options: '=',
multiple: '=',
enable: '=',
onChange: '&',
class: '#'
},
link: function(scope) {
scope.showOptions = false;
scope.displayValues = [];
scope.$watch('enable', function(enable) {
if (!enable && scope.showOptions) {
scope.toggleShowOptions(false);
}
});
scope.toggleShowOptions = function(show) {
if (!scope.enable) {
return;
}
if (show === undefined) {
show = !scope.showOptions;
}
if (show) {
$rootScope.$broadcast('fancySelect:hideAll');
}
$timeout(function() {
scope.showOptions = show;
});
};
scope.toggleValue = function(value) {
if (!value) {
return;
}
if (!scope.multiple) {
scope.model = value;
console.log(scope.model);
return;
}
var index = scope.model.indexOf(value);
if (index >= 0) {
scope.model.splice(index, 1);
}
else {
scope.model.push(value);
}
if (scope.onChange) {
scope.onChange();
}
};
scope.getDisplayValues = function() {
if (!scope.options || !scope.model) {
return [];
}
if (!scope.multiple && scope.model) {
return scope.options.filter(function(opt) {
return opt.id == scope.model;
});
}
return scope.options.filter(function(opt) {
return scope.model.indexOf(opt.id) >= 0;
});
};
$rootScope.$on('fancySelect:hideAll', function() {
scope.showOptions = false;
});
}
};
});
Updated
I tried to do as suggested in the answers by #Zidane and defining my object first in the controller like this:
$scope.year = {};
var saveUser = function(user) {
$scope.profilePromise = UserService.save(user);
console.log($scope.year);
This is the template:
<fancy-select
title="Klassetrinn"
model="year"
options="years"
enable="true"
on-change="onChangeYears()"
active="yearsActive"
name="playerYear"
form-name="registerForm"
>
</fancy-select>
But I got an empty object in that case.
When I define my objects like this I get the right value in the controller but in the view the title is not being displayed anymore:
$scope.search = {
years: []
};
var saveUser = function(user) {
$scope.profilePromise = UserService.save(user);
console.log($scope.search.years);
<fancy-select
title="Klassetrinn"
model="search.years"
options="years"
enable="true"
on-change="onChangeYears()"
active="yearsActive"
name="playerYear"
form-name="registerForm"
>
</fancy-select>
As you defined an isolated scope for your directive like this
scope: {
...
model: '=',
...
},
you give your directive a reference to an object on your controller scope.
Declaring the directive like <fancy-select model="myModel" ....></fancy-select> you pass your directive a reference to scope.myModel on your controller. When you modify a property on the scope.model object in your directive you automatically modify the same property on the scope.myModel object in your controller.
So you have to do
myApp.controller('myController', function($scope) {
...
$scope.myModel = {};
...
}
in your controller and in your directive just do
if (!scope.multiple) {
scope.model.value = value;
return;
}
Then you can get the value in your controller via $scope.myModel.value.
For clarification: You have to define an object on your controller and pass the directive the reference for this object so that the directive can follow the reference and doesn't mask it. If you did in your directive scope.model = 33 then you would just mask the reference passed to it from the controller, which means scope.model wouldn't point to the object on the controller anymore. When you do scope.model.value = 33 then you actually follow the object reference and modify the object on the controller scope.
you can use services or factories to share data between your angular application parts, for example
angular.module('myapp').factory('myDataSharing', myDataSharing);
function myDataSharing() {
var sharedData = {
fieldOne: ''
};
return {
setData: setData,
getData: getData,
};
function setData(dataFieldValue) {
sharedData.fieldOne = dataFieldValue;
};
function getData() {
sharedData.fieldOne
};
directive:
myDataSharing.setData(dataValue);
controller:
angular.module('myapp').controller('myController' ['myDataSharing'], function(myDataSharing) {
var myDataFromSharedService = myDataSharing.getData();
}
I'm trying get data from db to UI. Url given via provider is getting the data.
Controller in controller DetailsProvider.getDashboardDetails() is getting null.
var appmod = angular.module('project.DetailDashboardController', []);
appmod.controller("DetailDashboardController", ['$rootScope', '$scope', '$state', 'DetailsProvider',function($rootScope, $scope, $state,DetailsProvider) {
console.log("DetailDashboardController --- ");
$scope.DetList= DetailsProvider.getDashboardDetails()
}]);
})(window, window.angular);
provider which will call the list
(function(angular) {
var appmod = angular.module('project.DetailsServiceProvider', []);
appmod.provider('DetailsProvider', function() {
this.$get = ['_$rest', function DetailServiceFactory(_$rest) {
return new DetailsProvider(_$rest);
}];
});
function DetailsProvider(_$rest) {
this._$rest = _$rest,
this.getDashboardDetails = function(_callback, _data) {
var newData = null;
_$rest.post({
url: window.localStorage.getItem('contextPath') +'home/listdetail',
data: {} ,
onSuccess:_callback
}
});
}
};
})(window.angular);
Thanks in advance for any kind of reply!
You should return promise from your service method and do thenable in your controller.
Root Cause : your are returning the newData which will initalized later after completing the ajax call.Before completing it,you are returning the same variable which will be always null.
In provider,
(function(angular) {
var appmod = angular.module('project.DetailsServiceProvider', []);
appmod.provider('DetailsProvider', function() {
this.$get = ['_$rest', function DetailServiceFactory(_$rest) {
return new DetailsProvider(_$rest);
}];
});
function DetailsProvider(_$rest) {
this._$rest = _$rest,
this.getDashboardDetails = function(_callback, _data) {
var newData = null;
_$rest.post({
url: window.localStorage.getItem('contextPath') +'home/listdetail',
data: {} ,
onSuccess:_callback
}
});
}
};
})(window.angular);
and in controller,
$scope.list = function() {
DetailsService.getDashboardDetails(function(data){
varr holdIt = data.data.DList;
});
};
With the command console.log($scope.data) I can see my json file. I can also see the whole items in the view with <div ng-repeat="item in data"> but console.log($scope.data[0]) or console.log($scope.data[0].name) return an error "undefined"and console.log($scope.data.length) return 0.How can I access the items in the controller.
edit
$scope.data contain a json file. $scope.data = service.query(); and it looks like
I don't understand why is length return 0 when ng-repeat is working
It seems that you've stripped down all the relevant details (e.g. service.query implementation) from the question.
This plunker may shed some light on what's going on.
var app = angular.module('app', []);
app.factory('data', function ($timeout) {
var data = [];
return {
query: function () {
$timeout(function () {
data.push(1, 2, 3);
}, 1000);
setTimeout(function () {
data.push('Oops, ng-repeat is unconscious of this one');
}, 2000);
return data;
}
};
});
app.controller('AppController', function($scope, data) {
$scope.data = {
agile: [1, 2, 3],
lazy: data.query()
};
$scope.$watch('data.lazy', function (newVal, oldVal) {
if (newVal === oldVal) return;
console.log($scope.data.lazy[0]);
}, true);
});
Found this code while struggling with $http and $interval.
http://embed.plnkr.co/fSIm8B/script.js
Forked it to:
http://plnkr.co/edit/Al8veEgvESYA0rhKLn1q
To make it useful, how do I pass a variable to the service?
Broken code to show intent:
var myAppModule = angular.module("myApp", ['ngMockE2E']);
myAppModule.controller('MyController', function($scope, pollingService) {
var stopNow = 5;
var id = 1001;
pollingService(stopNow, id).then(
function(value) {
//fully resolved (successCallback)
$scope.data = value;
console.log('Success Called!');
},
function(reason) {
//error (errorCallback)
console.log('Error:' + reason);
},
function(value) {
//notify (notifyCallback)
$scope.data = value;
console.log('Notify Calls:' + value.count);
}
);
});
myAppModule.factory("pollingService", function ($http, $interval, $q, $httpBackend) {
var data = { resp: {}, status: 'Initialized', count: 0};
var deferred = $q.defer();
$httpBackend.whenGET("data.json").respond({type:'mock'});
//just loop 10 times for an example
var completed = $interval(function(ip) {
data.status = 'Running';
**//How can I Change the $http URL by passing a variable in?**
$http.get('/getId/' + id).then(function(r) {
data.resp = r.data.type;
data.count++;
**//Instead of 5 I want to pass this in as an variable**
if (data.count==stopNow)
{
$interval.cancel(completed);
}
console.log('Http\'s:' + data.count);
deferred.notify(data);
});
}, 500, 10);
completed.then(function(){
data.status = 'Completed!';
deferred.resolve(data);
});
return deferred.promise;
});
You can return a function in your service:
myAppModule.factory("pollingService", function ($http, $interval, $q, $httpBackend) {
return {
doSomething: function(arg1, arg2){
// Your code goes here
return deferred.promise;
}
}
And then on the controller
pollingService.doSomething(arg1,arg2).then(...)
I'm doing some small exercises to learn AngularJS, trying to understand how to work with promises at the moment.
In the following exercise, I'm trying to get some data async. I can see the data in the console.log but the promise is returned NULL.
GET /entries 200 OK
Promise is resolved: null
Anyone experienced can give me some advice to understand what I'm doing wrong ? Thanks for looking!
angular.module('questions', [])
.config(function($routeProvider) {
$routeProvider
.when('/', {
controller: 'MainCtrl',
resolve: {
'MyServiceData': function(EntriesService) {
return EntriesService.promise;
}
}
})
})
.service('EntriesService', function($http) {
var entries = null;
var promise = $http.get('entries').success(function (data) {
entries = data;
});
return {
promise: promise,
all: function() {
return entries;
}
};
})
.controller('MainCtrl', ['$scope', 'EntriesService', function($scope, EntriesService) {
console.log('Promise is resolved: ' + EntriesService.all());
$scope.title = "Q&A Module";
$scope.entries = EntriesService.all() || [];
$scope.addMessage = function() {
$scope.entries.push({
author: "myAuthor",
message: $scope.message
});
};
}]);
/****** Thanks everyone for your help so far *****/
After taking the advice of #bibs I came up with the following solution, that's clear using ngResource:
angular.module('questions', ['ngResource'])
.factory('EntriesService', function($resource){
return $resource('/entries', {});
})
.controller('MainCtrl', ['$scope', 'EntriesService', function($scope, EntriesService) {
$scope.title = "Q&A Module";
$scope.entries = [];
EntriesService.query(function(response){
$scope.entries = response;
});
$scope.addMessage = function() {
$scope.entries.push({
author: "myAuthor",
message: $scope.message
});
};
}]);
You should access the data in the callback. Since entries maybe empty before the data arrives, the all() function is not quite useful in this case.
Try this, you should be able to chain then() method to synchronously get data.
.service('EntriesService', function ($http) {
var services = {
all: function () {
var promise = $http.get('entries').success(function (data) {
entries = data;
}).error(function (response, status, headers, config) {
//error
});
return promise;
},
someOtherServices: function(){
var promise = ....
return promise;
}
return services;
}
});
$scope.entries = [];
EntriesService.all().then(function(data){
$scope.entries = data;
});
If you want the data returned by the server to be immediately reflected in your view:
.service('EntriesService', function($http) {
var entries = [];
var promise = $http.get('entries').success(function (data) {
for (var i = 0; i < data.length; i++) {
entries[i] = data[i];
}
});
return {
promise: promise,
all: entries
};
})
.controller('MainCtrl', ['$scope', 'EntriesService', function($scope, EntriesService) {
$scope.title = "Q&A Module";
$scope.entries = EntriesService.all;
$scope.addMessage = function() {
$scope.entries.push({
author: "myAuthor",
message: $scope.message
});
};
You may want to check out $resource to do this for you: http://docs.angularjs.org/api/ngResource.$resource