angular js Service/Factory attributes behavior - javascript

I have a question about AngularJS behavior (JS behavior in general)
I have an Angular factory injected into a controller.
Here's a snippet of the controller code
$scope.localObjCollection= myObjFactorySvc.getObjCollection();
Let's assume that myObjFactorySvc.getObjCollection() returns the following object
[{"id":1"name":null,"address":null,"email":null},
{"id":2"name":null,"address":null,"email":null},
{"id":3"name":null,"address":null,"email":null},
{"id":4"name":null,"address":null,"email":null},
]
So, I'm pretty much using the factory to get the collection and storing it in $scope.localObjCollection.
My question is does $scope.localObjCollection have the value (copy) of the data returned by getObjCollection() or just a reference.
So if somewhere down in the controller source code, if I do
$scope.localObjCollection.push(newObj), does it also update the original collection in the Factory? It should I guess but I would like to understand the correct behavior

An array in JavaScript is an object and objects in JS are always passed/assigned by reference. Therefore your code would also update the original collection in the Factory, assuming that your myObjFactorySvc.getObjCollection() is something like this:
myObjFactorySvc.getObjCollection = function() { return someArrayVariable; }

Related

Is it possible to change where AngularJS looks for variables?

Now, I know this is an off-the-wall question and that there is probably not going to be any API level access for doing this. I also understand that doing this is completely unnecessary. However, the implementation that I am aiming for requires for me to be able to make {{ variable }} look inside of the $scope.object instead of the $scope itself.
For example:
Controller($scope) {
$scope.active = ...;
}
In this case you can get the active object through {{active}} and any child elements through {{active.broken}} however for the sake of humoring me, lets assume that all of the variables I'm ever going to have to obtain is going to be part of that active object. So I'll be typing things like.. (Data not related)
{{active.title}}
{{active.author}}
{{active.content}}
You could just say "Well why not just move the title/author/content into the $scope and keep it outside of the active object, as that would achieve the desired result of this:
{{title}}
{{author}}
{{content}}
Well, that's where the problem comes in. This is a controller that is not exposed to my end-user, however the end-user does have a completely mutable object (in this example: active) that they can modify. This object has many [optional] listeners and callbacks that are invoked by the application controller when necessary.
The user's that have used my application during testing have commented on what a drag it is to have to type in active. before everything in order to get the data they wanted. Considering data from the $scope is never rendered to the screen, and only data from active is, I was wondering if perhaps there was a way to change where AngularJS looks when parsing/binding data.
If the goal is to evaluate expressions in a different context than $scope, that can be done with the $parse service.
app.controller("myVm", function($scope, $parse) {
var vm = $scope;
vm.active = { a: 5,
b: 3
};
var.myFn = $parse("a+b");
vm.total = myFn(vm.active);
console.log(vm.total);
});
The above example shows how to evaluate the expression a+b using the properties of the $scope.active object.
The DEMO on JSFiddle

Inject a factory in a controller in angular

I´m trying to inject a factory in a controller in Angular, but I can not do. It is my code.
app.controller('ManejadorEventosVista', ['AdministradorMarcador', ManejadorEventosVista]);
'app' is the variable that corresponds to the module with their respective dependencies. The controller is 'ManejadorEventosVista' and requires the services provided by the factory 'AdministradorMarcador'.
function ManejadorEventosVista(){}
but when I want to use the factory 'AdministradorMarcador' in this part of the code , the factory is not recognized.
ManejadorEventosVista.prototype.seleccionarMarcadorOrigen = function (){
AdministradorMarcador.setTipoMarcador(AdministradorMarcador.MARCADOR_ORIGEN);
};
How I can do to use the factory
'AdministradorMarcador' in ManejadorEventosVista.prototype.seleccionarMarcadorOrigen??..
Help or example to guide me??..Thanks..
ManejadorEventosVista needs to take an argument and you will be able to reference the AdministradorMarcador inside the function as whatever you named the first variable. Like so
function ManejadorEventosVista(AdministradorMarcador){/**your code here**/}
What you are doing with the line fragment ['AdministradorMarcador', ManejadorEventosVista] is declaring that your function depends on AdministradorMarcador, but without providing an argument to ManejadorEventosVista, AngularJS doesn't know how you intend to reference AdministradorMarcador inside your controller.
This is done in order to allow AngularJS scripts to be minified, especially by already existing solutions, as they would change the variables your function takes to single letter names, making it impossible for AngularJS to determine which service or factory to inject. Annotation uses strings and position-based ordering to allow your script to work, even after being minified since strings won't be altered by the process.
See also Latest Stable docs on Annotation

How exactly works this AngularJS factory example? Some doubts

I am absolutly new in AngularJS and I am studying it on a tutorial. I have a doubt related the use of the factory in Angular.
I know that a factory is a pattern used to create objects on request.
So in the example there is the following code:
// Creates values or objects on demand
angular.module("myApp") // Get the "myApp" module created into the root.js file (into this module is injected the "serviceModule" service
.value("testValue", "AngularJS Udemy")
// Define a factory named "courseFactory" in which is injected the testValue
.factory("courseFactory", function(testValue) {
// The factory create a "courseFactory" JSON object;
var courseFactory = {
'courseName': testValue, // Injected value
'author': 'Tuna Tore',
getCourse: function(){ // A function is a valid field of a JSON object
alert('Course: ' + this.courseName); // Also the call of another function
}
};
return courseFactory; // Return the created JSON object
})
// Controller named "factoryController" in which is injected the $scope service and the "courseFactory" factory:
.controller("factoryController", function($scope, courseFactory) {
alert(courseFactory.courseName); // When the view is shown first show a popupr retrieving the courseName form the factory
$scope.courseName = courseFactory.courseName;
console.log(courseFactory.courseName);
courseFactory.getCourse(); // Cause the second alert message
});
And this is the code, associated to this factoryController controller, inside the HTML page:
<div ng-controller="factoryController">
{{ courseName }}
</div>
So it is pretty clear for me that:
The factoryController use the courseFactory factory because is is injected
The first thing that happen when I open the page is that an alert mesage is shown because it is called the:
alert(courseFactory.courseName);
Then put into the $scope.courseName property (inside the $scope object) the value of the **courseName field of the courseFactory JSON object).
And here my first doubt. I have that the factory is defined by:
.factory("courseFactory", function(testValue)
that I think it means (correct me if I am doing wrong assertion) that my factory is named courseFactory and basically is a function that retutn the courseFactory JSON object.
So this is creating me some confusion (I came from Java) because in Java I call a factory class and I obtain an instance of an object created by the factory. But in this case it seems to me that doing:
$scope.courseName = courseFactory.courseName;
it seems to me that the courseName is retrieved directly by the courseFactory JSON object and I am not using the courseFactory.
How it exactly works? Why I am not calling some getter on the factory? (or something like this)
To simplify things There are two known methods to create functions ( and methods ) that are Usable among all states ( consider it as creating a function in global scope ) , these are factory and service.
you may want to read this first Factory vs Service
it seems to me that the courseName is retrieved directly by the
courseFactory JSON object and I am not using the courseFactory.
Actually this is partially true , as Angular use DI concept ( depency injection ) , you will have to inject your factory ( which by default returns an object , and corresponding functions as attributes ) , case you don't ; you will not be able to use your factory object methods.
Angular is not magic , it is just most people don't realize the most basic concepts of JavaScript , specially Developers coming from different programming environment such as C# , C++ , or Java
Easy.
When you return the courseFactory object in the factory statement, the injected courseFactory in the controller becomes THAT object. Therefore, when you do $scope.courseName = courseFactory.courseName; in the controller, you are actually referencing to the returned object that is injected into the controller as courseFactory. So you don't need a getter, because the courseFactory in your controller is already the object. You can do a console.log(courseFactory); in your controller to see what the courseFactory is. Hope this helps.
When an Angular application starts with a given application module,
Angular creates a new instance of injector, which in turn creates a
registry of recipes as a union of all recipes defined in the core "ng"
module, application module and its dependencies. The injector then
consults the recipe registry when it needs to create an object for
your application.
Ref. https://docs.angularjs.org/guide/providers
Factory is a Singleton service. When you inject the factory in the controller or in any other factory, u get the exact json object which u have defined. It will not create any new instance every time you call it. Factory is initialized only once

What's the secret to data-binding?

For most JS frameworks and libraries, the value they bring are often in the form of a new structure as to how to build an application (Backbone, React), or new ideas that effectively power-up the language (Angular), or simply the methods they offer are well tested, fast, and really convenient (jQuery).
Usually the ideas and methods they provide are pretty straightforward usage of JavaScript, but with a very clever team behind it that find interesting ways to do things which you can think through and get a solid guess as to how the guts work.
However, I've been unable to think through the ability to two-way bind JS models to view components. What is the secret sauce at the heart of this feature that makes this work? Changing an internal variable from a user input is simple, but what about the reverse? How would you be able to "know" when a JS variable has changed in order to update the display instantly? Surely it can't be polling, so what then?
Whenever a block of your JS runs that angular triggered it will run a digest cycle when the block finishes executing. This basically checks all the values that might of changed and would require updates to the view.
If angular didn't trigger the code then it won't know that something might of changed so your bindings can get out of sync. For example if you run something like this
setTimeout(function() {$scope.myValue = '123'});
Angular won't know that myValue changed and it actually won't update the view. That's why Angular has it's own services for doing everything. e.g. $timeout or $http.
If you have some callback function that Angular doesn't know about then you can manually tell it to check for changes by calling $scope.$apply()
there are several ways to do it. Object.observe is great, but lacks good support. You can poll for values as well, keeping a 2nd copy of the object around to compare. You can also write your own explicit set/get methods to update the model like backbone does.
One neat method i use a lot is using getters/setters to keep the model synced to the dom:
//a demo "model" of data:
model = {
name: "Fred"
};
function change(k,v){alert([k,v]);} // a stand-in change monitor for demo
// iterate model and replace values with getter/setter combos:
Object.keys(model).forEach(function(key) {
var val = model[key];
delete model[key];
Object.defineProperty(model, key, {
get: function() {
return val;
},
set: function(v) {
val = v;
change(key, val);
} //call change upon setting
});
change(key, val); //update view "onload"
}); // alerts "Fred";
//update model (fires change() with "name" and "sally" arguments:
model.name="sally"; // alerts "sally";
the change function is quite simple and for your case should just find elements bound to keys.
the advantage here is that you don't need special custom CRUD methods, you can just modify the object properties via assignment like it's 1999. It also doesn't poll, and works correctly all the way back to IE9 and any other ES5 environments. It's the simplest way to bind JS>DOM (afaik) without custom methods.
It does have some limits: nested objects are tricky to get/set upon, you can't do the whole object at once, you can only "watch" primitives. Arrays are a problem too: you can't really replace expando properties with getters/setters without side-effects. But, upon a relatively flat collection of JSON-safe data, get/set works a charm and needs no complex libs to get operational.
checkout a complete example using this method: http://pagedemos.com/xg3szbguqnwu/4
I can speak to how it's done in Backbone, which has a relatively low-level perspective on data-binding.
It's a combination of 1. the library having control over attribute setter methods 2. invoking callback functions when attributes change (e.g. by dispatching events) in order to update the UI.
The essential pseudocode is this:
class Model:
method set(name, value):
if value != this.attributes[name]
this.triggerEvent('change', name, value)
this.attributes[name] = value
m = new Model()
someInputWidget.onEvent('userChangedInput', function(value) {
m.set(someInputWidget.name, value)
})
m.onEvent('change', function(name, value) {
getInputWidgetByName(name).setValue(value)
})
Backbone does not do any data binding to the UI, but you can refer to Backbone's annotated source for the actual event-dispatching implementation.

Ember js: How to retrieve the underlying model from a controller

I am trying to retrieve the underlying model object from a controller so that it can be persisted (I am not using ember-data). The obvious way would simply be:
controller.get('content');
But this doesn't work. The problem can be summed up as follows:
controller.set("content", model);
sets the content as expected and at this point
controller.get('content');
works as expected. But if I then decorate the controller with other properties eg.
controller.set('IamNotPartOfTheModel', false);
then suddenly the 'content' includes this new property. I would've expected the content to remain unchanged and the new property to only be applied to the controller itself. I understand the controller is a proxy for the model so for the most part they are treated as one and the same but surely they should still be separable when needed? The whole point of this pattern is to separate data that should be stored from data that is just temporary. Am I missing something?
To have your display specific properties out of the model, just specify them explicitly in the controller... Otherwise the controller acts as a proxy for its model... just have the property "iamNotPartOfTheModel" in your controller
App.IndexController = Ember.ObjectController.extend({
iamNotPartOfTheModel: null
})
Sample fiddle here
Your controller needs to interface to some kind of model. You can't separate the persisted model from the controller except by some kind of object reference. Even if you don't use ember-data, you'll still need to create objects which then plug into the content of the controller. Have a look at Evil Trout's blog for an implementation of ember without ember-data. Its a great starting point.

Categories

Resources