ng-repeat in md-sidenav
<md-list>
<md-list-item ng-repeat="it in cars">
{{ it.name }}
</md-list-item>
</mdlist>
Car Controller
self.refreshUI = function(select) {
carService.getAllCars()
.then(function (res) {
$scope.cars = carService.carsList;
console.log($scope.cars);
}, function (err) {
//error
})
};
// Load all registered cars
self.refreshUI(null);
Above code runs when controller is loaded (last line) and it's working fine. But when I create new car (cars are stored in mysql db) and I want to update $scope.cars array by self.refreshUI() function it will not work until refreshing page mannualy.
console.log($scope.cars) from refreshUI function returns correct result but console.log(angular.element($0).scope().cars) gives wrong array (without new cars)
Car Service
function carService($q, $http) {
var cars = this;
cars.carsList = {};
cars.getAllCars = function() {
var defer = $q.defer();
$http.get("http://car.app/getCars")
.success(function(res) {
cars.carsList = res;
defer.resolve(res);
})
.error(function(err, status){
defer.reject(err);
});
return defer.promise;
};
return cars;
}
Where could be the problem?
//edit: $rootScope is working fine but i still want to use $scope
Why aren't you using a returned Promise as a result from the $http call? Besides of a better code style, it could solve your problem. With that kind of service-controller infrastructure I never had 'binding problems' like that.
function carService($q, $http) {
var cars = this;
cars.carsList = {};
cars.getAllCars = function() {
return $http.get('http://car.app/getCars').then(function (response) {
cars.carsList = response.data;
return response.data;
});
};
return cars;
}
In your controller you could then do something like that:
self.refreshUI = function() {
carService.getAllCars()
.then(function (data) {
// just obtain the promise data
$scope.cars = data;
}, function (err) {
// error handling
});
};
self.refreshUI();
Related
I understand that the appropriate method to share data between controllers in Angular.js is by using Factories or Services.
app.controller('Controller1', function($scope, DataService) {
DataService.getValues().then(
function(results) {
// on success
console.log('getValues onsuccess');
});
});
app.controller('Controller2', function($scope, DataService) {
DataService.getValues().then(
function(results) {
// on success
console.log('getValues onsuccess');
});
});
app.factory('DataService', function($http) {
var getValues = function() {
console.log('making http request');
return $http.get("/api/getValues");
};
return {
getValues: getValues
}
});
I have two controllers calling the same method in a factory twice
and this is perfectly fine and everything is working as it should. My only concer is that it seems a bit unecessary to make the same request twice? Would the use of $broadcast be a better approach?
Or could i structure my code differenty so that the service is called only once?
You could store the results of the request in the factory and retrieve those instead.
app.factory('DataService', function($http) {
var values;
var requestValues = function() {
console.log('making http request');
$http.get("/api/getValues").then(
function(results){
values = results;
});
};
var getValues = function() {
return values;
};
return {
requestValues : requestValues,
getValues: getValues
}
});
If your data is somekind of static and may not change very often over time you could do something like:
app.factory('DataService', function($http) {
self = this;
this.isLoaded = false;
this.results;
this.getValues = function() {
console.log('making http request');
$http.get("/api/getValues").then(
function(results) {
// on success
console.log('getValues onsuccess');
self.isLoaded = true
this.results = results;
return results;
})
);
};
})
And in the controller:
app.controller('Controller2', function($scope, DataService) {
if(!DataService.isLoaded){
results = DataService.getValues()
}else{
results = DataService.results;
}
});
You should consider caching in your DataService. Add a variable to hold the result from the http service and a time-stamp variable to store the time it was retrieved.
If a second call to the service is within a preset time period (lets say, 5 seconds), then http call is not made and data from the cache is returned.
app.factory('DataService', function($http) {
var cachedValue = null;
var lastGet = null;
var getValues = function() {
var timeNow = new Date();
if (cachedValue == null || ((timeNow - lastGet) < 5000)) {
console.log('making http request');
lastGet = timeNow;
cachedValue = $http.get("/api/getValues");
} else console.log('returning cached value');
return cachedValue;
};
return {
getValues: getValues
}
});
I'm very new to AngilarJS. I am trying to write a service in angularJS.
<script>
var module = angular.module("myapp", []);
module.service('BrandService', function ($http) {
var brands = [];
this.getBrands = function()
{
return $http.get('http://admin.localhost/cgi-bin/brand.pl')
.then(function(response)
{
brands = response.brands;
alert (brands);
});
}
//simply returns the brands list
this.list = function ()
{
return brands;
}
});
module.controller("brandsController", function($scope, BrandService) {
$scope.brandlist = BrandService.list();
alert ($scope.brandlist);
});
</script>
The statement "alert (brands);" is not getting called. What is the issue with this code. Is m missing any thing in implementation?
$http calls are always async. Meaning, even you do a .then at your service, there is no way it will properly the resolved data back into your controller. You will have to write it in your controller.
Your Service:
module.service('BrandService', function($http) {
var brands = [];
this.getBrands = function() {
//do not need the dot then.
return $http.get('http://admin.localhost/cgi-bin/brand.pl')
}
//simply returns the brands list
this.list = function() {
return brands;
}
});
In your controller:
module.controller("brandsController", function($scope, BrandService) {
BrandService.list()
.then(function(response) {
$scope.brandlist = response.brands;
alert($scope.brandlist);
});
});
In service:
this.getBrands = function() {
$http.get('http://admin.localhost/cgi-bin/brand.pl').then(function(response) {
brands = response.brands;
alert(brands);
return brands;
});
}
In controller:
$scope.brandlist = BrandService.getBrands();
alert($scope.brandlist);
In my controller, I'm calling a factory that fetches data from an API, then in the success function, the data is passed to another function that loops through it and calls another factory each round in the loop. The data retrieved from the second factory is then mashed up with the data from the first factory in a new object, each round in the loop, and pushed to an array.
When I add the data to the $scope, the view is being updated as the data is being fetched, you can see that the items in the view are added one by one and not all in a bunch.
I also need to sort the data in the $scope before it hits the view.
Is there a way to do this when all actions are finished? – When all data is fetched.
app.controller('MyCtrl', function($scope, firstFactory, secondFactory) {
var objArray = [];
function doStuff() {
firstFactory.getData().success(function(data) {
doMore(data);
});
}
function doMore(data) {
$.each(data, function(key, value) {
secondFactory.getData(value).success(function(result) {
var obj = {
test: result.test,
test2: value.test
};
objArray.push(obj);
});
});
$scope.data = objArray;
}
});
For the second call you can use $q.all. This would get resolved only when all the calls are complete
function doMore(data) {
var promises = [];
$.each(data, function (key, value) {
promises.push(secondFactory.getData(value));
});
$q.all(promises).then(function (responseArray) {
$.each(responseArray, function (result) {
var obj = {
test: result.test
};
objArray.push(obj);
});
$scope.data = objArray;
});
}
You can chain promises. A promise in the chain is only run when the previous has executed, or you can even run promises in parallel and with $q.all wait for all promises to finish.
Here is a sample that might help you plunker:
var app = angular.module('plunker', []);
app.factory('dataFactory', function($http, $q) {
var getData = function() {
var combinedData = [];
var deferred = $q.defer();
$http.get('first.json')
.then(function(data) {
return data;
})
.then(function(data) {
firstData = data;
$http.get('second.json').then(function(secondData) {
angular.forEach(firstData.data, function(value, key) {
combinedData.push(value);
});
angular.forEach(secondData.data, function(value, key) {
combinedData.push(value);
});
deferred.resolve(combinedData);
});
});
return deferred.promise;
};
return {
getData: getData
};
});
app.controller('MainCtrl', function($scope, dataFactory) {
$scope.items = [];
var onSuccess = function(data) {
$scope.items = data;
};
var onError = function() {
console.log('error');
};
dataFactory.getData()
.then(onSuccess, onError);
});
I'm using the services directive in Angularjs not factory and I need to populate a json file to local variable;
/* Contains projects on the town */
leMaireServicess.service('cityService', function($http) {
// JSON regions and cities loader
this.cities = [];
// initCities
this.initCities = function() {
this.cities = $http.get('data/census/cities.js').success(function(data) {
return data;
});
return this.cities;
};
// Get city info
this.getCity = function() {
return this.cities;
};
});
And in my controller I have
// Saved game controller
leMaireControllers.controller('GameCoreCtrl', function($scope, cityService) {
/* Control the town project slides */
cityService.initCities();
$scope.city = cityService.getCity();
console.log($scope.city);
});
But instead of returning the actual data, it returns;
Object {then: function, catch: function, finally: function, success: function, error: function}
You can use a watch to make this work (see plunker)
var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope,cityService) {
//$scope.cities = [];
$scope.service = cityService;
cityService.initCities();
$scope.$watch('service.getCity()', function(newVal) {
$scope.cities = newVal;
console.log(newVal)
});
});
app.service('cityService', function($http) {
var that = this;
this.cities = [];
this.initCities = function() {
$http.get('data.js').success(function(data) {
that.cities = data.cities;
});
};
this.getCity = function() {
return this.cities;
};
});
$http returns a promise which is what you're setting this.cities to.
This might help explain more,
https://stackoverflow.com/a/12513509/89702
In your controller you should be able to do something like this...
cityService.initCity().then(function(data) { $scope.city = data; }
You are working with promises which represent the result of an action that is performed asynchronously. Try it this way:
leMaireServicess.service('cityService', function($http) {
this.promise = {};
// initCities
this.initCities = function() {
this.promise = $http.get('data/census/cities.js');
};
// Get city info
this.getCity = function() {
return this.promise;
};
});
And in the controller you need to put your code in a callback:
// Saved game controller
leMaireControllers.controller('GameCoreCtrl', function($scope, cityService) {
/* Control the town project slides */
cityService.initCities();
cityService.getCity().then(function(result){
$scope.city = result.data;
console.log($scope.city);
});
});
Hi I have two controllers
pqsAppModule.controller('NotificationBoxController',function($scope,items) {
$scope.list = items.list();
})
and
pqsAppModule.controller('NotificationController',function($scope,items) {
$scope.list = items.list();
})
I need to create an "items" service that would do an ajax request and return data for any controller which would have it injected. And I want, that the query will be done only once, and items will be shared between all controllers.
pqsAppModule.factory('items', function($http) {
var items = [];
var itemsService = {};
$http.get('api/notification').then(function(response){
items = response.data;
});
itemsService.list = function() {
return items;
};
return itemsService;
});
But I don't understand why angular makes the request, and receives data, but all items in controllers are empty.
It happens because the factory should be defined by different way.
(I took dummy URL only to load data by async way)
HTML
<div ng-controller="NotificationBoxController">
<button ng-click="showMe();">press me</button>
<pre>NotificationBoxController: {{items.getList()|json}}</pre>
</div>
<div ng-controller="NotificationController">
<pre>NotificationController: {{items.getList()|json}}</pre>
</div>
JS
var pqsAppModule = angular.module('myApp', []);
pqsAppModule.controller('NotificationBoxController',function($scope,items) {
$scope.items = items;
$scope.showMe= function(){
items.query();
}
});
pqsAppModule.controller('NotificationController',function($scope,items) {
$scope.items = items;
});
pqsAppModule.factory('items', function ($http) {
var current = {};
var address = 'Singapore, SG, Singapore, 153 Bukit Batok Street 1';
var URL = 'http://maps.googleapis.com/maps/api/geocode/json?address=' + address + '&sensor=true';
var factory = {
query: function () {
var data = $http({method: 'GET', url:URL}).then(function (result) {
current = result.data.results[0];
}, function (result) {
alert("Error: No data returned");
});
},
getList: function () {
return current;
}
}
return factory;
});
Demo Fiddle
From this example we call items.getList() from HTML for both controllers. But if we want to update the model through the controller, we need a listener like $watch
Try this
$http.get('api/notification').then(function(response){
angular.foreach(response.data,function(item) {
items.push(item);
});
});
Basically do not create a new array but fill the existing one.