I'm currently migrating my application from $resouce to Restangular and I'm having trouble understanding where extendModel should be implemented.
Having read through the slides available here on slide 46 it shows the following two snippets.
Restangular.extendModel('cars', function(car){
return Car.extend(car);
});
module.factory('Car', function(Exteder){
function Car(){}
Car.prototype.chargeFuel = function(amount){
}
Car.extend = Extender.for('car')
return Car
});
My question is where should the extendModel function actually be declared? Should it be in the App.config or in a controller somewhere? I've been through the documentation several times now and I can't seem to find a concrete answer.
So after much searching I believe I've found the correct place to implement this as being in the app.config section of the angular application.
Simply pass the RestangularProvider as a parameter and use RestangularProvider.extendModel()
Related
I'm doing Angular JS tutorials. I've no clue why this notation have been used. Can anyone explain what is happening here?
Code in the controller.js file:
var vm = this;
vm.openSideBar = openSideBar; // Did not understand this line
function openSideBar() {
$mdSidenav('left').open();
};
The code that you post is purely stylistic and takes advantage of hoisting to enable the bindable functions to be displayed at the top of the file, and the details (implementations) for those to be kept separate and specified further down the file.
Benefits
The benefits of this approach are more apparent as the number of bindable functions in the controller increases:
Easier to read (what's important). Since the purpose of the controller is to support the view and supply it with bindings, the what is more important than the how i.e. What the view can bind to is more important than how the controller goes about it's work. You can see immediately on opening the file what the controller can do for the view.
Easier to find (the details). Having the bindable functions at the top of the file acts as like a contents page for the file. Most IDE's will highlight matching variables if you place the cursor over them and that helps find the implementation details further down the file.
Encourages single responsibility. Your controller should be supplying bindings for a view, and only one view. You can see at the top of your file if you start to build up lots of unrelated bindable functions that serve different purposes that you might be trying to do too much in one controller.
Encourages named functions. This is particularly useful for debugging as it means that you will have less anonymous functions in your application, which in turn makes reading call stacks in developer tools easier.
Further Reading
Check out John Papa's Angular 1 Style Guide which has been approved by the Angular team. You can read all about the thought behind this approach under the heading Bindable Members Up Top in the Controllers section (although it can be applied to factories/services/directives also).
openSideBar was add to view model. it was aviable to run this func from view like <someElement ng-click="$ctrl.openSideBar()"></someElement>
The VM model or way of doing is quite old... before ES6 came along.
Nowadays, I would suggest you learn ES6, take a look at Todd Motto's AngularJS style guide https://github.com/toddmotto/angularjs-styleguide.
But here an answer to your question:
// OLD WAY
function MyAppController() {
var vm = this;
vm.colors = ['red', 'blue', 'green'];
vm.getBlue() {
return vm.colors[1];
}
vm.handleClickEvent(e) {
// this keyword is now the dom element, not your controller
// this is why the VM pattern came to life.
this.classList.add(vm.getBlue());
}
}
// NEW WAY
class MyAppController {
$onInit() {
this.colors = ['red', 'blue', 'green'];
}
getBlue() {
return this.colors[1];
}
handleClickEvent(e) {
// Here this keyword is still your controller, NOT the dom
// element (provided you used angular's ng-click directive
const elem = e.target;
elem.classList.add(this.getBlue);
}
}
With ES6, it is rare that you have to same a reference to this since you can use arrow functions. You should also get familiar with bind(), call(), and apply() methods to control which context you want to apply to functions.
I am currently working on implementing a REST API with Angular resource 1.2.x. I just came across several hints that with the 1.2.x release, angular-resource broke some existing patterns. My question is now, how to handle the following scenario with angular-resource 1.2.x correctly.
I do have a REST API that returns data (/offers/:id) and a angular service that abstracts those API by using angular-resource. Within this service I do have a get function that queries the API with the given id:
_offerResource.get({offerId: id})
The _offerResource itself is an instance of $resource.
In my controller, I do have a variable offer on the $scope to which the view is bound (e.g. $scope.offer.title, ...).
I tried to implement the call to the API with the following line of code:
_tempOffer = OfferAPI.get($routeParams.offerId)
But unfortunately the bindings are not working. Based on this SO entry (Angularjs promise not binding to template in 1.2) the behavior of angular-resource has changed. But is the approach with using the $promise.then(...) statement the way to go? From an engineering point of view this looks quite ugly, as I need to take care of this in the controller, rather than the service returning me an object that I just can use.
This one works, but as stated above, it is not my favorite approach from a SW design point of view:
_tempOffer = OfferAPI.get($routeParams.offerId)
_tempOffer.$promise.then((response) ->
$scope.offer = Offer.initializeFromJSON(response.offer)
)
I convert the response of the API into another object btw, so I need to have the following transformation before I can bind the offer object to the $scope.offer variable:
$scope.offer = Offer.initializeFromJSON(response.offer)
Thanks a lot for your help!
Recently I was thinking about the differences and similarities between Backbone.js and AngularJS.
What I find really convenient in Backbone are the Backbone-Models and the Backbone-Collections. You just have to set the urlRoot and then the communication with the backend-server via Ajax basically works.
Shouldn't it be possible to use just the Backbone-Models and Collections in AngularJS application?
So we would have the best of both worlds two-way data-binding with AngularJS and convenient access to the server-side (or other storage options) through Backbone-Models and Collections.
A quick internet search didn't turn up any site suggesting this usage scenario.
All resources either talk about using either the one or the other framework.
Does someone have experience with using Backbone-Models or Collections with AngularJS.
Wouldn't they complement each other nicely? Am I something missing?
a working binding for example above...
http://jsbin.com/ivumuz/2/edit
it demonstrates a way for working around Backbone Models with AngularJS.
but setters/getters connection would be better.
Had a similar idea in mind and came up with this idea:
Add just a getter and setter for ever model attribute.
Backbone.ngModel = Backbone.Model.extend({
initialize: function (opt) {
_.each(opt, function (value, key) {
Object.defineProperty(this, key, {
get: function () {
return this.get(key)
},
set: function (value) {
this.set(key, value);
},
enumerable: true,
configurable: true
});
}, this);
}
});
See the fiddle: http://jsfiddle.net/HszLj/
I was wondering if anyone had done this too. In my most recent / first angular app, I found Angular to be pretty lacking in models and collections (unless I am missing something of course!). Sure you can pull data from the server using $http or $resource, but what if you want to add custom methods/properties to your models or collections. For example, say you have a collections of cars, and you want to calculate the total cost. Something like this:
With a Backbone Collection, this would be pretty easy to implement:
carCollection.getTotalCost()
But in Angular, you'd probably have to wrap your custom method in a service and pass your collection to it, like this:
carCollectionService.getTotalCost(carCollection)
I like the Backbone approach because it reads cleaner in my opinion. Getting the 2 way data binding is tricky though. Check out this JSBin example.
http://jsbin.com/ovowav/1/edit
When you edit the numbers, collection.totalCost wont update because the car.cost properties are not getting set via model.set().
Instead, I basically used my own constructors/"classes" for models and collections, copied a subset of Backbone's API from Backbone.Model and Backbone.Collection, and modified my custom constructors/classes so that it would work with Angular's data binding.
Try taking a look at restangular.
I have not implemented it anywhere, but I saw a talk on it a few days ago. It seems to solve the same problem in an angular way.
Video: http://www.youtube.com/watch?v=eGrpnt2VQ3s
Valid question for sure.
Lot of limitations with the current implementation of $resource, which among others doesn't have internal collection management like Backbone.Collection. Having written my own collection/resource management layer in angular (using $http, not $resource), I'm now seeing if I can substitute much of the boilerplate internals for backbone collections and models.
So far the fetching and adding part is flawless and saves code, but the binding those backbone models (or the attributes within, rather) to ng-models on inputs for editing is not yet working.
#ericclemmons (github) has done the same thing and got the two to marry well - I'll ask him, get my test working, and post the conclusion...
I was wondering the same-
This is the use-case:
salesforce mobile sdk (hybrid) has a feature called smartstore/smartsync, that expects backbone models/collection ,which gets saved to local storage for offline access .
And you guessed it right, we want to use angularjs for rest of the hybrid app.
Valid question.
-Sree
You should look at the angularJS boilerplate with parse here. Parse is backbone like, but not exactly backbone. Thats where im starting my idea of a angularJS backboneJS project
I am on way to learning backbonejs.
I am working with the popular todo list tutorial.
I have certain questions about which i am a bit confused:
In one the models i found this function:
toggle: function() { this.save({completed: !this.get(’completed’)});}
The thing that i don't understand is this.save function. How does it work? What does it actually saves and where. And what does the code inside this function means: completed: !this.get and so on.
In one of the views i found this line of code:
this.input = this.$(’#new-todo’);
Now what does this.input means? And i also don't understand the sytnax this.$('#new-todo');
Let me know if more code is needed for comprehension. Also if anyone could point me to great learning resources for backbone, it will be awesome. Currently i am learning from 'Backbone Fundamentals' by addyosmani.
Backbone Model and Collection both have url properties.
When set properly backbone will make a HTTP POST request with the model as a payload to the url when saved for the first time (id property has not peen set). I you call save and the models id has been already set, backbone will by default make PUT request to the url. Models fetch function generates a GET request and delete a DELETE request.
This is how backbone is made to work with RESTfull JSON interfaces.
When saving a model you can define the actual model to save like it's done in the example.
Read the Backbone.js documentation. It's ok!
http://backbonejs.org/#View-dollar
this.$('#new-todo') // this.$el.find('#new-todo')
toggle: function() { this.save({completed: !this.get(’completed’)});}
Its basically saving inverse value to "completed" attribute of model. so if model's current attribute is true, it would save it to false !
regarding this.input = this.$(’#new-todo’);
Its basically saving/caching DOM with id "new-todo" from current VIEW's 'el' to view instance's 'input' property. so that we do not have to call jQuery methods for getting the same element when we need in future.
hope this helps.
:)
I too am a backbone newbie and i had been in search of good tutorials that gave good insights into the basics and i found after around 3-4 days of searching. Go through backbonetutorials.com and there is a video compiled which gives exactly what we need to know about Routers, Collections, Views and Models.
The sample working can be found at : http://backbonetutorials.com/videos/beginner/
Although this tutorial is a very basic one, you need to have basic jquery, javascript knowledge. Keep http://www.jquery.com opened in another tab as well when you go through the sample codes. Documentation is extremely useful.
Once you have good knowledge of jquery then if you go through the tutorials, you will understand and pick it up a lot better. And once you get hold of the MV* pattern of backbone you'll love it.
p.s : Do not copy paste codes or functions if you need to learn, type them.!!..
Cheers
Roy
toggle: function() { this.save({completed: !this.get(’completed’)});}
Backbone Model have a url property, when you set a property backbone makes a HTTP request to that url to save that value to the data source.
Here it is setting the value of "completed" attribute with inverse of earlier "completed" value, which will be saved to the data source
I've decided that I am going to try and learn backbone.js by making a web app. This is the first time I have done anything extensive in javascript, so the answer to my problem may be right in front of my face.
I have the web app on github, along with a running version that doesn't work. The javascript console just says that something is undefined when I don't think it should be. Here's the error that chrome gives for line 30 of app.js:
Uncaught TypeError: Cannot read property 'el' of undefined
I've sort of been referencing the backbone-fundamentals example modular to-do app, and it doesn't seem to have any issues with a similar thing.
If anyone could point out what I am doing wrong, I would be most appreciative!
Thanks in advance!
Your Machine view render method was missing return this and by default all methods return undefined - that's why chaining didn't work
Edit: and a small tip:
jQuery, Underscore and Backbone register globally - and thanks to that you don't have to define them as dependencies every time - it's enough if you require them in your main script once and after that you can access them from the global scope as you normally would
In my case i was returning this without the return keyword. As i was using javascript and not coffeescript it failed on me. So, if you are using javascript use return this; instead of just this in the last line of the render() function.
I also had a problem when using this.collection.on('reset', this.render(), this). I instead had to use this.collection.on('reset', this.render.bind(this));