Can I use $rootScope for factory to update view? - angularjs

i'm started so ths is very elementar question.
I have a simple factory:
angular.module('notes', ['ngResource']).
factory('Notes_module', function ($resource) {
var Notes_items = $resource(BASE_URL + 'xxx/:method/:guid', {},
{
get_all: {method: 'GET', params: {method: 'get_all'}, isArray: true }
});
return Notes_items;
}
);
and controller to show note_items.
function Notes($scope, Notes_module) {
$scope.notes = Notes_module.get_all();
};
Now in my view I have simple button to get new notes_items from server:
<a ng-click="synchronize()">
and the controller:
function LeftBardController($scope, Queries_module) {
$scope.synchronize = function() {
$scope.notes = Queries_module.get_all_new_note();
};
}
the new factory for check new items:
angular.module('queries', ['ngResource']).
factory('Queries_module', function ($resource) {
var Queries_items = $resource(BASE_URL + 'xxx/:method/:guid', {},
{
get_all_new_note: {method: 'GET', params: {method: 'get_all_trash'}, isArray: true },
});
return Queries_items;
}
);
And the question is.
When I click on button 'synchronize' the database are updated ok.But the view are not refresh. When I refresh page then the view are also refresh.
When I change $scope in my controller to $rootScope (save notes in rootscope) it automatically refresh view as i want and it's great - but it is a good way to use $rootScope. How can i do this in other way ?
I read about $apply but when add it to my controller i does not work.

Related

AngularJS : Render controller without waiting factory variable to be intialized first

First, I'm new to angularjs. I've create a factory to handle most of my data named "store". Here is an example:
app.factory('store', function ($rootScope, $http, $q, api) {
var data = {};
return {
setData: function () {
var deferred = $q.defer();
$http({
method: 'GET',
url: api.getData()
}).then(function successCallback(response) {
// handle data
$rootScope.broadcast('store:data', data);
deferred.resolve();
}, function errorCallback(reponse) {
// do stuff
deferred.reject();
});
},
getData: function () {
return data;
},
addData: function (newData) {
// do stuff
},
editData: function (newData) {
// do stuff
},
deleteData: function (newData) {
// do stuff
}
};
});
I'm initializing this data inside my app.run function. BUT, I don't want my app to wait my data to be initialized first to render the controller. I want it to be rendered first and wait for updating when the data is initialized.
store.setData()
.then(function (response) {
// do stuff
})
.catch(function (response) {
// do stuff
});
Here is how I'm getting the data updated inside my controller to be rendered
$scope.data = store.getData();
$rootScope.$on('store:data', function (event, data) {
$scope.data = data;
})
SO my problem is that I don't want to wait my data to be initialized to render my controller.
Is there a solution to this problem ?
Thanks a lot.
EDIT May 20 2021
Btw if what I'm doing is wrong and there is better things to do, I'm open to any suggestions ! Thnx
EDIT June 9 2021
Now I'm using $resource, but I don't know how can I get the new version of my list of data when I add new element to it.
agents: $resource(
api.getAgents(),
{},
{
get: {method: 'GET', isArray: false, cache: true},
add: {method: 'POST', url: api.addAgent(), hasBody: true},
edit: {method: 'PUT', url: api.editAgent(), params: {agentId: '#id'}, hasBody: true},
delete: {method: 'DELETE', url: api.deleteAgent(), params: {agentId: '#id'}},
}
),
Waiting for an answer. Thank you vm !
There are a couple options you can consider, but first a note on best practices in AngularJS and JavaScript: avoid the deferred antipattern. The $http service returns a promise. You should work with that rather than creating a new promise with $q.defer.
The first option is to change the getData method to return a promise instead of the actual data. It is a good idea to always design your data retrieval services to return promises, even when you intend to pre-retrieve and cache the data. This provides the cleanest way to ensure that the data is available before you try to use it. In your example, you should be able to internally cache the promise rather than the data. So your code would change to something like this:
app.factory('store', function ($rootScope, $http, api) {
var dataPromise;
return {
setData: function () {
dataPromise = $http({
method: 'GET',
url: api.getData()
}).then(function successCallback(response) {
// handle data
$rootScope.broadcast('store:data', data);
}, function errorCallback(reponse) {
// do stuff
});
},
getData: function () {
if (!dataPromise) {
this.setData();
}
return dataPromise;
},
// etc.
};
}
You will of course have to change the code that calls the getData method to work with the promise instead of working directly with the data.
Another option is to use an AngularJS Resource. This feature works very much like your original intent by returning an instance of an object that at some point will get populated with data. It takes advantage of the AngularJS change detection to render the data once it becomes available. Resources also have the ability to cache responses internally so that the call to the server is only made once. Rewriting your service as a resource would look something like this:
app.factory('store', function ($rootScope, $resource, api) {
return $resource(
api.getData(), // the base URL
{}, // parameter defaults
{ // actions
getData: {
method: 'GET',
cache: true
},
// etc.
}
);
}

Make an object for angularJS controller using $resource (factory|service)?

My approach is using AngularJS Service instead of factory along the project. Now I want to build an object called MyData which should be used as array in angularJS controller, such as:
vm.datas= MyData.query({}, function (datas) {
vm.thisData = {selected: datas[0].id};
});
As I searched in questions, I understood I can use factory as below:
angular.module('myDataService', ['ngResource']).
factory('MyData', function($resource){
return $resource(myURL, {}, {
query: {method:'GET', isArray:true}
});
});
What should I do if I want to use service. Is the code correct, below? What is the best practice?
angular
.module('app')
.service('myDataService', myDataService);
myDataService.$inject = ['ngResource'];
function myDataService($resource) {
var self = this;
self.MyData = $resource(myURL, {}, {
query: { method: 'GET', isArray: true }
});
}

Angular Resource error in console

I ve got an angular resource service which then returns the data to a controller and I get all the data plus the data by name.
My application works just fine in the browser but I get a resource error in the console. Bad resource configuration.
I had a look in various questions and everyone states that I need to set the configuration property isArray to either false or true.
I have tried to do this but I still get an error.
Any ideas much appreciated.
Here is my service :
(function() {
var app = angular.module('test');
app.service('ContactResource', function($resource) {
return $resource('/contacts/:firstname', {},
{'update': {method: 'PUT'}},
{'query': { method: 'GET', isArray: true }},
{'get': { method: 'GET', isArray: false }}
);
});
}());
And here is my controller:
(function() {
var app = angular.module('test');
app.controller('contactsCtrl', function($scope, $routeParams, ContactResource) {
$scope.contacts = ContactResource.query();
$scope.singlecontact = ContactResource.get({firstname: $routeParams.firstname});
});
}());
The error I am getting is : Error: [$resource:badcfg] http://errors.angularjs.org/1.4.2/$resource/badcfg?p0=get&p1=object&p2=array&p3=GET&p4=%2Fcontacts
When I click it says :
Error in resource configuration for action get. Expected response to contain an object but got an array (Request: GET /contacts)
When I get the url is /contacts the response is :
[{EmailAddress:some#email.com, etc}]
When the url is /contacts/firstname the response is :
{EmailAddress:some#email.com,etc}
I solved the problem by adding a new controller called single controller and by separating the service into two functions. Here is how my code looks like now.
This is the service:
(function() {
var app = angular.module('test');
app.service('ContactResource', function($resource, $routeParams) {
this.all = function() {
return $resource('/contacts', {},
{'query': { method: 'GET', isArray: true }}
)};
this.single = function() {
return $resource('/contacts/:firstname', {firstname: '#firstname'},
{'query': { method: 'GET', isArray: false }}
);
}
});
}());
And the controllers :
(function() {
var app = angular.module('test');
app.controller('contactsCtrl', function($scope, $routeParams, ContactResource) {
$scope.contacts = ContactResource.all().query();
});
app.controller('singleCtrl', function($scope, $routeParams, ContactResource) {
$scope.singlecontact = ContactResource.single().query({firstname: $routeParams.firstname});
});
}());
For some reason which I am still not sure $resource wouldn't accept them into the same controller.

using the variables from factory tu update the content

I am trying to understand the logic of this factory thing. How can I use those variables, like save, drop, update. Can i use them like this ? X . Or i have to write something else to success.
app.factory("Inventory", function($resource){
return $resource(
"http://localhost/api/v1/inventory/:Id",
{Id: "#Id"},
{
update: {
method: 'POST',
params: {"update": true},
isArray: false
},
save: {
method: 'PUT'
},
create: {
method: 'POST'
},
drop: {
method: 'DELETE'
}
}
);
});
You need to define a controller and inject the dependency on it for you to be able to use this factory.
Example:
app.controller('myController', function($scope, Inventory) {
$scope.drop = Inventory.drop;
});
in your html:
<div ng-controller='myController'>
X
</div>

Angularjs: a Service that serves multiple $resource urls / data sources?

I have an Angular service/provider that serves json data to my controller which works great:
angular.module('myApp.services', ['ngResource']).
factory("statesProvider", function($resource){
return $resource('../data/states.json', {}, {
query: {method: 'GET', params: {}, isArray: false}
});
});
But I also need to serve json data to the same controller from another file counties.json.
Where can I find out how to I write a service that serves both files to my controller?
You can update service to return a hash of resources, not a single one:
angular.module('myApp.services', ['ngResource']).
factory("geoProvider", function($resource) {
return {
states: $resource('../data/states.json', {}, {
query: { method: 'GET', params: {}, isArray: false }
}),
countries: $resource('../data/countries.json', {}, {
query: { method: 'GET', params: {}, isArray: false }
})
};
});
You will be able to use it adding .query() at the end your function name i.e. geoProvider.states.query() and geoProvider.countries.query() and myApp.services has to be injected into your controller, then inject geoProvider service into controller itself as well.
I'm assuming you want to execute some code when both files have loaded. Promises work really well for this. I don't think resources return promises, but you can use the $http service for simple ajax calls.
Here I define one service each for the two data files, and a third service that returns a promise that gets fulfilled when both files are done loading.
factory('states',function($http) {
return $http.get('../data/states.json');
}).
factory('countries',function($http) {
return $http.get('../data/countries.json');
}).
factory('statesAndCountries', function($q, states, countries) {
return $q.all([states, countries]);
});
Then in your controller:
statesAndCountries.then(function(data) {
var stateData = data[0];
var countryData = data[1];
// do stuff with stateData and countryData here
});

Resources