When page is loading first time, I'm getting my thingsList filled. But then I need choose option with ng-click, it triggers function doSomething() which is getting new thingsList. I can see at debug mode that there is a new list, but there's no binding and datatables still showing me the old thingsList.
I'd really like to solve this without dtOptions is it's possible.
I'm using pretty simple "angular way" with datatables:
<tr ng-repeat="thing in thingsList">
<td>{{thing.id}}</td>
<td>{{thing.name}}</td>
</tr>
and my controller looks like:
.controller('ThingsController', ['$http', '$scope', function ($http, $scope) {
this.getThing = function () {
$http.get(....).then(
function success(response) {
$scope.thingsList = response.data;
},
function error(data) {
console.log(data);
}
);
};
this.getThings();
this.doSomething = function (id) {
$http.get(....).then(
function success(response) {
$scope.thingsList = response.data;
},
function error(data) {
console.log(data);
}
);
};
}]);
Try using
$scope.thingsList.splice(0); // clears the array without losing reference
Array.prototype.push.apply($scope.thingsList, response.data); // inserts new data to existing array
instead of $scope.thingsList = response.data; in doSomething function.
So I'm guessing the reason its happening is because the getThings() function is being called every time the controller is used. You might want to modify your controller code in this way and try:
.controller('ThingsController', ['$http', '$scope', function ($http, $scope) {
$scope.getThing = function () {
$http.get(....).then(
function success(response) {
$scope.thingsList = response.data;
},
function error(data) {
console.log(data);
}
);
};
$scope.doSomething = function (id) {
$http.get(....).then(
function success(response) {
$scope.thingsList = response.data;
},
function error(data) {
console.log(data);
}
);
};
}]);
Now this will solve your problem of the list not updating when you choose your option with ng-click but your list won't get loaded by default when you load the page since getThings() isn't being called.
My suggestion for that would be to use use ng-init as described in the answer to this question:
How to execute angular controller function on page load?
or better yet use $scope.on in this manner in your code:
.controller('ThingsController', ['$http', '$scope', function ($http, $scope) {
$scope.getThing = function () {
$http.get(....).then(
function success(response) {
$scope.thingsList = response.data;
},
function error(data) {
console.log(data);
}
);
};
$scope.$on('$viewContentLoaded', function() {
$scope.getThing();
})
$scope.doSomething = function (id) {
$http.get(....).then(
function success(response) {
$scope.thingsList = response.data;
},
function error(data) {
console.log(data);
}
);
};
}]);
In case you're using routing you can change the '$viewContentLoaded' to '$routeChangeSuccess' for ng-route or '$stateChangeSuccess' if you're using ui-router. (Don't worry about this unless you're using routes to change views)
Related
I'd like to create dynamically controllers responsible for view of data from REST API. My idea is to use ng-repeat directive with data from service and inside it create object with ng-controller directive with parameter from ng-repeat output (The most important condition is that each one question must have its own $scope). Unfortunatelly I don't know how to pass data from service.
AngularJS service code
(function () {
'use strict';
angular
.module('App')
.factory('questionsDataService', questionsDataService);
questionsDataService.$inject = ['$http'];
function questionsDataService($http) {
return {
getMetadata: function (taskId) {
var metaData = $http.get('api/toDo/taskVariables/' + taskId).then(
function (response) {
return response.data;
});
return metaData;
},
getQuestionsData: function (taskId) {
var questionsData = $http.get('api/toDo/getQuestions/' + taskId).then(
function (response) {
return response.data;
});
return questionsData;
}
}
}
})();
I'm not sure if I understood the question, your title is misleading, but I will show how to get the data from the service. I don't think you need a new controller for each item in an ng-repeat, but without more info on why you are trying to do this, I can't help there.
(function () {
'use strict';
angular
.module('App')
.controller('myController', myController);
// you are injecting your service here, this will be whatever the string is from the .factory() call
myController.$inject = ['$scope', 'questionsDataService'];
// again, we are passing the service in to the controller function
function myController($scope, questionsDataService) {
// your service calls are returning promises
// this will get run when the controller is initialized
questionsDataService.getMetadata(1).then(function(data){
// here is where you can access the returned metadata
// save it to the scope so you can access it in the DOM
console.log(data);
})
// if you want to call your service on a button click, or with some other function
$scope.getQuestions = function (id) {
questionsDataService.getQuestionsData(id).then(function (data) {
// here is where you can access the returned data
// save it to the scope so you can access it in the DOM
console.log(data);
})
}
// I added a service method that returns a string, rather than a promise
// this will get run when the controller is initialized
var str = questionsDataService.getServiceName();
console.log(str);
}
})();
(function () {
'use strict';
angular
.module('App')
.factory('questionsDataService', questionsDataService);
questionsDataService.$inject = ['$http'];
function questionsDataService($http) {
return {
getMetadata: function (taskId) {
var metaData = $http.get('api/toDo/taskVariables/' + taskId).then(
function (response) {
return response.data;
});
return metaData;
},
getQuestionsData: function (taskId) {
var questionsData = $http.get('api/toDo/getQuestions/' + taskId).then(
function (response) {
return response.data;
});
return questionsData;
},
// adding this just to show you how to access functions that don't return promises
getServiceName: function () {
return "questionsDataService";
}
}
}
})();
Im just starting on AngularJS. I'm not sure how to churn this out. I'm trying to include multiple functions within one service. (I hope this is not against bad practice.)
The following is my working code:
myDataService.async().then(function (d) {
$scope.dbCalls = d.d;
});
My Service:
app.factory('myDataService', function ($http) {
// How do you get this bottom line to work?
// this.getAllCalls = function () {
var myService = {
async: function () {
var promise = $http.post('AngularTest.aspx/FetchCalls', { data: {} }).then(function (response) {
console.log(response);
return response.data;
});
return promise;
}
};
return myService;
//}; <--Commented out for clarity
});
Thanks!
you just return an object with properties from the service, then you are able to call those properties as different service methods
like so:
.service('myService', function() {
return {
firstMethod: function() { ... },
secondMethod: function() { ... },
thirdMethod: function() { ... }
}
})
and in the controller/directive
.controller('myCtrl', function(myService) {
myService.firstMethod();
myService.secondMethod();
myService.thirdMethod();
})
Hey guys i'm new to angular and am not very proficient with javascript. This setup pulls in the json data fine, however when I make changes to some of the properties in the object, they reset when I change views and the controller is reloaded. Any help or guidance on how to approach this would be appreciated.
app.controller('MainCtrl', function ($scope, $location, Quiz) {
$scope.quiz = {};
Quiz.getQuestions(function(data) {
$scope.quiz = data;
});
});
app.service('Quiz', function($http) {
this.getQuestions = function(callback) {
$http.get('questions/questions.json').success(function(data) {
if (callback) {callback(data);}
return data;
});
};
});
Does the $http get request get repeated on subsequent calls to getQuestions() overwriting the object? If so, perhaps
app.service('Quiz', function($http) {
var _data;
this.getQuestions = function(callback) {
if (_data) {
callback(_data);
}
$http.get('questions/questions.json').success(function(data) {
_data = data;
if (callback) {callback(data);}
return data;
});
};
});
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