Using the same object instances across the app in Angular.js - javascript

I'd like to know how would be a good way to store data in angular.js that will be accessed across the app from different controllers. I'm using restangular to access the data on the backend. I have my own services to access the data, something like this:
app.factory('models.user', function(Restangular) {
var users;
users = {};
return {
get: function(user_id) {
return users[user_id] || (users[user_id] = Restangular.one('users', user_id).get());
}
};
});
For all models I define a service to access it. Using this, from any place of the app when I call User.get(1) I get the same model instance.
I'd like to find a better way to do so. What do you guys do in to keep the same instances in your Angular.js apps?

This is the pretty best way. Why do you confused by this code?

Related

Update view after AJAX call succeeds and returns data

I'm a beginner working on a recipe search app which returns a list of recipes based on the ingredients the user puts in the search bar. I'm learning to use Angular since it's convenient and makes my code more manageable.
So far I have succeeded in making jQuery Ajax GET requests to the API of my database and have a list of JSON objects returned.
Here's my Angular controller declaration:
var recipesData = []; // variable that will hold the returned data
angular
.module("awesomeapp")
.controller("listController", listController);
function listController () {
var vm = this;
vm.data = recipesData;
}
And I have stuff in vm.data displayed elsewhere in my view.
The problem is, when vm.data is set to recipesData, it doesn't contain anything yet because the page has just been loaded, the user hasn't put anything in and there isn't any data returned yet.
What should I do so that vm.data can be set after the Ajax call? Or can it be set outside of the listController function?
I'm looking for an elegant solution for this so that it makes everything easier to maintain. Thank you :)
The proper way to do this is to not use jQuery and use Angular's $http service to retrieve the data. The even more proper way to do this is to create your own service that internally uses Angular's $http service to get the data.
So first you would create the service. Something like this:
angular
.module("awesomeapp")
.service("recipeService", recipeService);
function recipeService($http) {
return $http.get(**url**)
}
Then your controller would look like something this:
function listController (recipeService) {
var vm = this;
recipeService.then(response) {
vm.data = response.data
}
}
You'll probably have more things on your service eventually, but that should get you going in the right direction. I'd highly recommend referring to John Papa's Angularjs style guide https://github.com/johnpapa/angular-styleguide/blob/master/a1/README.md for guidance on how to structure your app. You want to try to avoid using jQuery with Angular in general, but in particular, you want to avoid using it for things Angular does natively.

how to get json data from a angular service using jquery

I am setting data from a angular controller to a service. I need to somehow get this data using jquery or javascript.Is this possible since I am not requesting it from a url?
Angular service
getSeriesData: function () {
return this.legendSeries;
},
setSeriesData: function (legendSeries) {
this.legendSeries = legendSeries;
},
Not sure why you would want to do that (if you explain the scenario better it might help), but in case you want to share data between an angular application and other JS code (e.g. JSON), one way you could go about is to dispatch a global event from the angular service [for example $(window).trigger('myEvent', myJSON] and then catch this on your separate JS code [window.addEventListener('myEvent'...]
Seems like possible using injector
var injector = angular.element('body').injector()
$injector.invoke(function (serviceName) {
var legendSeries = service.legendSeries;
service.setSeriesData(legendSeries);
});

AngularJS reusable factory

I feel like this is probably a dumb question but I'm having trouble visualizing how to make this work.
I have a factory used to share data between controllers, like this:
app.factory('DataShare', function(){
//Share Data between controllers via the sharedItem object and the get/set functions
var sharedItem = {};
function set(sharedData){
sharedItem = sharedData;
}
function get(){
return sharedItem;
}
return{
set: set,
get: get
};
});
It works just fine. The issue is that are several times in my application where I need to share data. Currently, I have multiple factories with different names containing the same methods shown above. Can someone advise on the best way to create an abstract factory that I could reuse to share different data between different controllers?
Create a new file and declare a new object.
var mySharedLib = mySharedLib || {}; // declare a new namespace for the shared code.
mySharedLib.DataShare = function() {
// your factory logic
}
Then, the angular side:
app.factory('DataShare', mySharedLib.DataShare);

What is the AngularJS equivalent to Backbone's Collections?

Is there an equivalent to Backbone's Collection or Ext JS's Store in Angular JS? I'm learning about $resource, but not quite getting this aspect.
Controller
// This is the "collection" I'm interested in.
$scope.foos = [];
// Foo is a $resource.
Foo.query(function (foos) {
// This works, but is there a smarter "collection" object?
$scope.foos = foos;
});
$scope.createFoo = function (data) {
var foo = new Foo(data);
foo.$save(function (shinyNewFoo) {
$scope.foos.unshift(shinyNewFoo);
});
};
Explanation
In $scope.createFoo I'm making a new Foo, persisting it, then adding it to my poor man's collection, an array. This works and the view is updated correctly, but I'm too lazy for this. Ideally, I'd like to have a "collection" I can add to and remove from that will automatically POST/DELETE. Maybe something like the following.
Pretend Implementation
$scope.fooCollection = new CoolCollection({
// specify the type of resources this collection will contain
itemsResource: Foo
});
// Creates new Foo, saves, adds to collection.
$scope.fooCollection.add(data);
Does something like this exist? The $resource docs mention a collection, but I didn't really get it. This answer seemed promising, but didn't explain the collection idea. Am I missing something or just not thinking about this the Angular way?
Addendum
In the MEAN.io boilerplate, the article controller suggests that the "collection" is managed manually (see the splice below).
$scope.remove = function(article) {
if (article) {
article.$remove();
for (var i in $scope.articles) {
if ($scope.articles[i] === article) {
$scope.articles.splice(i, 1);
}
}
} else {
$scope.article.$remove();
$location.path('articles');
}
};
If this elusive "collection" existed, I suppose they would have used it. Instead, they're managing an array manually.
AngularJS does not define any kind of structured data model. This part is entirely up to you.
The $resource service is just a wrapper on top of the lower-level $http service; it defines a high level way to fetch your data from the server and has little to do with how you structure your data on the frontend.
If a more sophisticated frontend data model is required by your application, you should investigate other JS libraries or roll your own. However, angular's singleton services and powerful two-way data binding make this unnecessary for most small/medium applications.

how to model my data is angular js? Does something like Backbone.Model will fit?

I am using angular-js and I am looking for a way to model my data. I am inspired by Backbone and started to write something similar to Backbone model. In Backbone model there are get() and set() methods for accessing model's members.
What is the advantages of using get() and set() methods over using model.attributes.__?
If I don't need my angular models to trigger changes events, does it worth to create get() and set() methods that are similar to Backbone.Model's get() and set()?
EDIT
To be more clear, I am asking if there is advantage to make a set() and get() methods over direct access to the fields. If there is no any advantage, why does Backbone people decided to go that way?
You just need to create a service which would hold the data, you can think of services like instances of models or collections. For example, you have some domain class like Book, what you can do is to create a service 'BookListService' which would be responsible for CRUD and/or business logic.
Something like this
function Book(title, author){
this.title = title;
this.author = author;
this.isRead = false;
}
Book.prototype.markAsRead = function(){
this.isRead = true
}
angular.module('someModule', []).factory('BookListService', function($http){
var service {
books: [],
load: function(){
$http.get('/books').then(function(res){
angular.forEach(res.data, function(book){
service.books.push(new Book(book.title, book.author))
})
})
}
};
return service;
})
Angular's 'models' are any object in javascript.
If you check out the tutorials on angularjs.org,
http://jsfiddle.net/api/post/library/pure/
The data is defined in the Controller. So make an array, just do
$scope.todos = [
{text:'learn angular', done:true},
{text:'build an angular app', done:false}];
To get/set is just normal javascript:
get length: $scope.todos.length;
set to empty: $scope.todos = [];
In the view (html), just call the variable if its under the same Controller
<div ng-controller="TodoCtrl">
<span>{{todos.length}}</span>
</div>
I had some trouble with this at first because Angular seems overwhelming, so I was expecting a big answer for model implementation. The answer is simply to use JS objects. Angular has all of the tools you need to easily create a model yourself without the use of Backbone (which I have also read is not really the way to go with Angular). If you look into $emit, $broadcast, $on, you have your events for model updates. If you want to create instances of the objects rather than singletons, then have your factory return an instance. A good place to start I think is angular-app. Apologies if this isn't specific enough.
If you are looking for a package to use, try BreezeJS.

Categories