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);
});
Related
I created a simple AngularJS service with .factory() called $getUser that gets data from users.json:
{
"john": {
"name": "John",
"address": "New York"
},
"bob": {
"name": "Bob",
"address": "Boston"
}
}
Now I want to use this data in mainController:
angular.module('myApp', [])
.factory('$getUser', ['$http', function($http){
var users = {};
$http.get('users.json').then(
function(response) {
users.data = response.data;
}
);
return users;
}])
.controller('mainController', ['$getUser', function($getUser){
// I can access whole $getUser object
console.log($getUser);
// but when I want to access $getUser.data it gives me 'undefined'
console.log($getUser.data);
}]);
When I want to console whole $getUser object, it works, but I am not able to access $getUser.data property. Why?
Create factory as:
app.factory('$getUser', ['$http', function($http) {
var factory = {
query: function () {
return $http.get('users.json').then(function (response) {
return response.data;
}, function (result) {
alert("Error: No data returned");
});
}
}
return factory;
}]);
So you can call it as:
$scope.data = $getUser.query()
Simple demo Fiddle
However I suggest to return promise and resolve it in controller
The common approach to load JSON is:
app.factory('Items', ['$http',
function($http) {
return {
getJson: function(url) {
var ItemsJson = $http.get(url).then(function(response) {
return response.data;
});
return ItemsJson;
}
}
}
]);
and Usage:
var jsonPromise = Items.getJson('jsonData/someJSON.json');
jsonPromise.then(function (_response) {
// ...
}, function (error) {
console.error(error);
});
try this:
angular.module('myApp', [])
.factory('$getUser', ['$http', function($http) {
var users = {};
return {
getData: function() {
return $http({
url: 'users.json',
method: 'GET'
})
}
}
}])
.controller('mainController', ['$getUser', function($getUser) {
// I can access whole $getUser object
console.log($getUser);
// but when I want to access $getUser.data it gives me 'undefined'
console.log($getUser.data);
$getUser.getData().then(function(data) {
console.log(data.data);
});
}]);
Fiddle Link
I'm pretty new to angular js, currently, it's going well but now I have a question.
I have a template with a topnav and a contentpart. All with its own controller.
With a button I can open a "submenu" where I can choose data from the database, within the "Liquid"-section. Thats working pretty well.
Since the Topnav is rendered at the login of the page, the topnav wont be rendered again.
If I add a Liquid in the content section, I have to reload the data behind the "Liquid"-Dropdown.
That dropdown is encapsulated in a directive:
function liquidselect(Data){
return {
restrict: 'AE',
templateUrl: 'views/controls/liquid_select.html',
scope: {
selectedValues : '='
},
link: function(scope) {
},
controller: function ($scope) {
//
Data.post('ownrecipes').then(function (results) {
$scope.searchRes = results;
});
// debugger;
//$scope.searchRes = RecipeDataService.data;
$scope.disabled = undefined;
$scope.searchEnabled = false;
$scope.searchRes = [];
$scope.flavoring = {amount: {}};
$scope.updateModelValue = function (selected) {
// console.log(selected);
//
$scope.selectedValues = selected;
};
}
}
}
The communication to the server is done by a factory:
app.factory("Data", ['$http', 'toaster',
function ($http, toaster ) { // This service connects to our REST API
// var deffered = $q.defer();
var serviceBase = 'api/v1/';
var obj = {};
obj.toast = function (data) {
toaster.pop(data.status, "", data.message, 3000, 'trustedHtml');
}
obj.get = function (q) {
return $http.get(serviceBase + q).then(function (results) {
return results.data;
});
};
obj.post = function (q, object) {
return $http.post(serviceBase + q, object).then(function (results) {
return results.data;
});
};
obj.put = function (q, object) {
return $http.put(serviceBase + q, object).then(function (results) {
return results.data;
});
};
obj.delete = function (q) {
return $http.delete(serviceBase + q).then(function (results) {
return results.data;
});
};
return obj;
}]);
How can I update/reload the data of the directive from a child scope? Is there any chance?
Here is a plunker which showcases my problem and want I want to do:
http://plnkr.co/edit/bNANkQYZfBaS4CHH3dwX
I hope it's helpful for you :-)
Layout:
Basic Layout
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
I have a service which will make a call to the server and returns the data. I am binding service to a variable on scope.
Example:
Let the service be DataModelService
in the controller : $scope.data = DataModelService
in the view <div ng-repeat="value in data.persons">{{value.name}}</div>
My Code :
This is how my code looks like:
/**DataModelService**/
factory('DataModelService', [
'DataService',
function (DataService) {
var service;
service = {
changeState: function (params) {
DataService.changePersonState(params)
.then(function (response) {
service.loadData(response.data);
});
},
loadData: function (responseData) {
service.persons = responseData.persons;
}
}
return service;
}
]);
/**DataService**/
factory('DataService', ['$http',
function ($http) {
return {
changePersonState: function (params) {
return $http.post("url", params);
}
}
}
]);
/**DataController**/
.controller('DataController', ['DataModelService',
function (DataModelService) {
$scope.data = DataModelService;
}
]);
/view/
<div ng-repeat = "person in data.persons" >{{person.name}} </div>
On the view I am doing a ng-repeat on a key in data i.e. ng-repeat="value in data.persons"
and also I have an option to change the state of person to active or inactive, so whenver i make a change to the state of the person, a call is sent to the server and data is set into the Service and as it is binded to the view, it should automatically update the data. But whats happening in my case, ng-repeat is not removing old data and instead it is appending new data to the old data.
For me its not good approach to write promise callback (then) into service. Because in your case, DataModelService returns data with some delay but not promise. And we don't know when.
So the way to make it work to add basic $timeout and fetch data from service by using other method.
So my suggestion is Demo
and your fixed example: Demo2
If we will take your example, it should be like:
JS
var fessmodule = angular.module('myModule', ['ngResource']);
fessmodule.controller('fessCntrl', function ($scope, DataModelService, $timeout) {
$scope.alertSwap = function () {
DataModelService.changeState('ff');
$timeout(function(){
$scope.data = DataModelService.getResponse();
}, 10);
}
});
fessmodule.$inject = ['$scope', 'Data', '$timeout'];
/**DataModelService**/
fessmodule.factory('DataModelService', [ 'DataService',function (DataService) {
var value = [];
var service = {
changeState: function (params) {
DataService.changePersonState(params)
.then(function (response) {
value = response.persons;
});
},
getResponse : function(){
return value;
}
}
return service;
}
]);
/**DataService**/
fessmodule.factory('DataService', ['$q',function ($q) {
var data = { // dummy
persons: [{
name: "Bob"
}, {
name: "Mark"
}, {
name: "Kelly"
}]
};
var factory = {
changePersonState: function (selectedSubject) {
var deferred = $q.defer();
deferred.resolve(data);
return deferred.promise;
}
}
return factory;
} //function
]);
I am trying to listen to changes in my injected service (self-updating) in the controller. In the below example you'll find two $watch cases - one that works but I don't know exactly why and one that was obvious to me, yet doesn't work. Is the second example the right way to do it? Isn't that code duplication? What is the right way to do it?
Service:
app.factory("StatsService", [
'$timeout', 'MockDataService',
function ($timeout, MockDataService) {
var service, timeout;
timeout = 5000;
service = {
fetch: function () {
// Getting sample data, irrelevant, however this is what updates the data
return this.data = MockDataService.shuffle();
},
grab: function () {
this.fetch();
return this.update();
},
update: function () {
var _this = this;
return $timeout(function () {
return _this.grab();
}, timeout);
}
};
service.grab();
return service;
}
]);
Controller:
app.controller("StatsController", [
'$scope', 'StatsService',
function ($scope, StatsService) {
var chart;
$scope.stats = StatsService;
$scope.test = function (newValue) {
if (arguments.length === 0) {
return StatsService.data;
}
return StatsService.data = newValue;
};
// This doesn't work
$scope.$watch('stats', function (stats) {
return console.log('meh');
});
// This works, don't know why
$scope.$watch('test()', function (stats) {
return console.log('changed');
});
}
]);
See the third parameter for $watch: objectEquality
Compare object for equality rather than for reference.
However if you're only interested in watching the returned data, then you should do:
$scope.$watch('stats.data', function (stats) {
return console.log('meh');
});
You could use $rootScope events. For example inside the service you could dispatch an event with $rootScope.$broadcast("somethingFetched", data) and catch it in the controller $scope.$on("somethingFetched", function(event, data) { $scope.data = data }).
More details you could find in the documentation http://docs.angularjs.org/api/ng.$rootScope.Scope