First I create some backbone views:
(function() {
var SomeView = Backbone.View.extend({ ... });
// finally on ready
$(function() {
// init my view
var v = new SomeView({...});
});
})();
Now, as we can see, I am instantiating the view inside the jQuery ready function, and assigning the instance to a local variable, which will be lost once the function exits. But, I notice that my view just works perfectly -- i.e., even though I am losing the reference to the view, it just works.
I guess this is because there are many closures involved, and all the required variables are actually preserved inside those closures.
So, my question is: is this alright to instantiate the views like this. Is it OK to not save the reference to it.
If you never need a reference to the view again, this is totally fine. You can render the view after instantiating it (or even do it in its constructor) and it will insert the generated HTML in the DOM (depending on the options you have set on the view).
Of course if you need to call some view methods later from some code outside the view you will need to keep a reference to the view around somewhere.
Your understanding is correct, if you do not need to call this view from the outside, then of course you do not need to record this reference.
However, your example is too simple, the actual situation of general need to record this reference.
btw:There are a lot of backbone of best practice, and I hope useful for you: http://ricostacruz.com/backbone-patterns
Related
I have been struggling a long way in a issue, wherein I need to update a parent obj from directive scope. I need to fetch some data using $http and fit this data against a property in original parent Obj.
However, after doing this, the view gets updated but somehow the model binded to these view become undefined. Since the view are updated with new data, somehow the models are becoming undefined after that.
Only now I came to know that, $http triggers a $digest, so I think that is the cause of my issue.
What can I do to avoid my models becoming undefined and the fetched values to remain intact in original object.
Just to make things clear, before I attach a wrking plnkr. here is what I mean:
I have a obj $scope.Obj. I have binded the input fields in directive template with this object using 2 way binding like
<input ng-model = Obj.something.something2[$index]/>
Now say I made a API call and update my something2 in $scope.Obj as:
$scope.Obj.something.something2 = APIResponse.something3
The values from new object something3 are visible on UI, but in backend after this
$scope.Obj.something.something2[$index]
becomes undefined.
Pls suggest possible reasons for this...
The other models are becoming undefined because you are replacing the object. Instead you should use angular.extend.
angular.extend($scope.Obj.something.something2, APIResponse.something3);
For more information see the AngularJS angular.extend API Reference.
This is somewhat a follow up on my "Is it bad practice for an angular directive to request data" Q.
My Q Is where would be the appropriate place to keep application data?
for example - information about the current user such as his name and his roles in the app?
differrent areas (on the screen) and components will depend on this data (e.g - side bar will want to know if the curentUser.isAnAdmin and a helloUser Directive would like to know the currentUser.name
Does this mean that the currentUser should be placed on the $rootScope?
and what should be the trigger for retrieving the initial data for the currentUser and for refreshing this information?
I was thinking of having several ngControllers responsible for setting up this data on the scope of the same html node as that of the ngApp, but found out that it is not possible to have multiple ngControllers on a single HTML Item.
I am now thinking of having multiple services with methods that get a scope object and assign the data they are responsible to onto that scope.
It would allow me to separate code for currentUser from code for someOtherSharedAppData into two different services and call both of them from the applications's main controller thus assiging the data to the scope associated with the top-most element in the app - does that make sense?
In fact you asked two questions here:
Where to store and manipulate data?
When and how should I use the $rootScope (compared to $scope)?
1)
I will refer to this article:
Whenever data and methods need to be reusable I would write a service like this for example.
angular.module('modelDemo').service("myModel", [function() {
this.list = [what, ever, items, you, have];
this.property= null;
this.setProperty = function(value) {
this.property= value;
};
}]);
Note, that I'm not passing the $scope as you considered. Instead I would inject the service in my controller and bind the $scope variables like this:
$scope.list = myModel.list;
If you need, you can even bind to the full model
$scope.myModel = myModel;
myModel.setPropery(value)
Got the idea? This way all model changes will be directly available to the corresponging view
{{myModel.property}}
ng-repeat="item in myModel.list"
ng-click="myModel.setProperty(item)"
Conclusion: Yes, you should have different services for your user model and your someOtherSharedAppData models.
2)
I will refer to this SO Question.
In short: If you have data that should be available in many views, it is OK to bind your (service) model to $rootScope variables. As you can see in the mentioned discussion there are also other opinions but I think the conclusion is: It depends on the structure and needs of your application.
Here's something simple and I think there must be a better way: I often need to navigate to a new view, and at the same time I want to provide some context information to the scope that will be created. I can't figure out how to do both simply -- change the url (resulting in my view/controller being instantiated) and pass some variables I want instantiated in the controller's scope -- for instance, so they can be rendered in the view template
So instead I am doing:
$rootScope.myVar = 'blah';
$location.path = '/newView' ;
and newView.html accesses {{myVar}}
I know this is wrong, what is the simplest solution to avoid using $rootScope like a global dumping ground?
I use a same controller twice on my page, with same data, but i display it not in the same way (not same parts of the array).
I can see with ng-inspector that the scope is correctly updated when i perform some change, and it's duplicate. But in the view, it's doesn't change ! A simple param to false by default and passed at true with a simple timeout, in the view, it's always to false.
If i display only one time the ng-controller, the view it's updated.
How to correct that ?
Ok, so you didn't actually give much in the way of code, but this sounds like you're falling victim to one of the classic scope blunders. The first thing to try is to use properties of objects, not primitives on the scope.
This means instead of using this code ---
$scope.myBool = false;
{{myBool}}
use this code ---
$scope.myBool = { value: false };
{{myBool.value}}
The reason being is that Angular likes to do funny stuff like use prototype for new scopes. This means you'll get the prototype of the parent scope, and then when you instantiate your scope, you can override the parents prototype with your new value, without changing the parents value. You get past this by using an object on the scope instead.
The second option that might be occurring is you're doing something that isn't causing an angular digest cycle to happen. You might need to manually kick one off.
Without seeing any code, there's no telling, though.
I find that when creating applications using angular the $scope starts to feel messy as there's so much added to it, and there's actually no way of restricting the properties and methods assigned to the scope. In my opinion it becomes very hard to keep it clean and overseeable.
I have created a module that wraps around the $scope object, which then takes 2 objects to predefine properties and methods that are allowed on the scope, like so (note that the exact code is not the issue here):
// set which scope properties are valid. currently returns $scope
// I was not able to properly extend $scope with new getter/setters
// note that this contains the FULL overview of valid properties on scope.
$scope = enforcer.init(
$scope,
{ "foo": null, "bar": null /* object with valid properties */ },
{ "doFoo": null, "doBar": null /* object with valid methods */}
);
// set the actual property on the scope, could be anywhere in the controller
enforcer.set('foo', 'baz');
enforcer.set('doFoo', function () { /* ... */ });
// try to set an invalid property on the scope -> error
enforcer.set('biggle', 'boggle');
However, as I'm not overwriting native getters/setters this means I have to call things like enforcer.set() to add a variable to the scope. This will in turn match the predefined properties to see if the desired property is actually predefined and will throw an error if it's not. Unfortunately this also kind of breaks my auto-completion in the editor. Next to that, scope references from the HTML are also not checked and can be pretty wild. I could bind on anything and not find a typo in the bound var for hours.
I have not been able to find a proper way of redefining the getter/setter of the scope, and even if I did I could not be sure this would not break when angular updates the original $scope object.
What are your suggestions on keeping the scope strict and clean? I'd like the scope to feel the same as any variable in javascript, requiring a declaration (i.e. var foo; before being allowed to use it.
The scope should only serve as a wiring tool which links together services, factories and resources. Thus, the rule of thumb is that the scope should do very little, and if you feel that your scope is cluttered by too much variables, it means that probably you should start thinking about refactoring your code.
Read point 3 of this article: AngularJS antipatterns and pitfalls