Object assignment does not work in this angularjs controller - javascript

Inside my angularjs controller, I try to assign an object into a $scope.XX object. For some reason, it cannot work. Here is a simplified version of the code inside the angularjs controller.
$scope.XXX = {};
polling_interval_ms = 100;
var poll = function (ChartObj, polling_interval_ms) {
var processedObj = {};
processedObj = processDataChart(data_Chart); //data_Chart is object that contains data that changes in real-time
ChartObj = Object.assign(processedObj);
console.log(ChartObj);
$timeout(function () {
poll(ChartObj, polling_interval_ms)
}, polling_interval_ms);
};
poll($scope.XXX, polling_interval_ms);
console.log($scope.XXX);
The strange part is the output of console.log(ChartObj); shows that data has been assigned to the object. However, the output of console.log($scope.XXX) is empty. I was expecting $scope.XXX to contain same data as ChartObj. What did I do wrong?

In javascript all parameters in function is reference. So when you change reference - you not change referenced object.
In your case you can use Object.assgin in a bit different way
Object.assign(ChartObj, processedObj);
because
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
Or pass wrapper for object XXX, in this case it a $scope
$scope.ChartObj = {};
polling_interval_ms = 100;
var poll = function (wrapper, polling_interval_ms) {
var processedObj = {};
processedObj = processDataChart(data_Chart); //data_Chart is object that contains data that changes in real-time
wrapper.ChartObj = Object.assign(processedObj);
console.log(wrapper.ChartObj);
$timeout(function () {
poll(wrapper, polling_interval_ms)
}, polling_interval_ms);
};
poll($scope, polling_interval_ms);
console.log($scope.ChartObj);

Use
$scope.XXX
instead of ChartObj because
your are assigning value to
ChartObj
and
$scope.XXX
is not a refrence type

Related

How can set an outer variable value in a Javascript constructor pattern?

I have the following situation. I'm trying to create an object that will be initialized then reused over the course of a script. Part of the construction of such an object requires a login to retrieve data from a webpage. This data will be kept within the object.
Consider a file called myThingAbove.js that contains this code:
module.exports = (function(){
//need to keep these updated
var a = {}, b = {};
const myThing = function(options){
somefun(args, function(err, resp){
//stuff
a = valueBasedOnResp;
b = valueBasedOnRespAsWell;
});
})
mything.prototype.myMethod = function(args) {
// makes use of a and b
}
return myThing;
})());
I'm initializing this "object" as follows:
const myThing = require('./myThingAbove.js');
const myObj = new myThing(args);
myObj.myMethod();
It looks like I'm not able to maintain a or b's state. The constructor call with the new statement sets these values as expected but they do not persist with myObj. How can I maintain the values of these variables within my instance of myObj?
I'm using NodeJS v8.5.0.
UPDATE: It's been pointed out that myObj.myMethod() and const myObj = new myThing(args); will be executed asynchronously. This may actually be my problem. Is there a way to guarantee myObj will be constructed before myObj.myMethod() is called?

In Javascript, why should instance variables with reference type be put in the constructor?

Reading an excerpt from Google developer insights:
https://developers.google.com/speed/articles/optimizing-javascript#initializing-instance-variables
Place instance variable declaration/initialization on the prototype for instance variables with value type (rather than reference type) initialization values (i.e. values of type number, Boolean, null, undefined, or string). This avoids unnecessarily running the initialization code each time the constructor is called. (This can't be done for instance variables whose initial value is dependent on arguments to the constructor, or some other state at time of construction.)
For Example, instead of:
foo.Bar = function() {
this.prop1_ = 4;
this.prop2_ = true;
this.prop3_ = [];
this.prop4_ = 'blah';
};
Use:
foo.Bar = function() {
this.prop3_ = [];
};
foo.Bar.prototype.prop1_ = 4;
foo.Bar.prototype.prop2_ = true;
foo.Bar.prototype.prop4_ = 'blah';
I understand the logic behind putting variables with value type into the function prototype, but aren't we running the initialization code when we have a reference variable like this.prop3_ = []; (as per Google example)? Does this not create a new array with every invocation of the constructor?
Instance properties of reference types need to be added to the constructor otherwise when added to the prototype, each instance of the constructed object would share the same reference. It's OK when just reading information, but problem occurs when modyfing. Please check the following example
var Test = function () {
this.foo = [];
};
Test.prototype.bar = [];
var instance1 = new Test();
var instance2 = new Test();
instance1.foo.push(1);
instance1.bar.push(1);
instance2.foo.push(2);
instance2.bar.push(2);
console.log(instance1.foo, instance1.bar); // [1], [1,2]
Although instance1.bar.push was called only once, the array has two values, because instance1.bar and instance2.bar are the same array, shared by two objects.

Instances Conflicting - JSON objects

I'm not doing something right.
Trying to create 2 instances of data models off my json model template file and use them but I'm obviously not getting 2 different instances of the model.
myModel.json
{
"id": null
}
myNodeModule.js
var myModel = require('../../entities/myModel');
module.exports = {
find: function *(id){
var myModelInstance1 = myModel;
myModelInstance1.id = 1;
var myModelInstance12 = myModel;
myModelInstance12.id = 2;
found.push(myModelInstance11);
found.push(myModelInstance12);
console.log("id: " + found[0].id);
}
Problem: it logs "2" because for some reason it applies the last initialization for myModel1.
So how do you create 2 separate object instances of myModel.json?
Create a function instead, which returns the object and call it.
function myModelFact(){
return {
"id": null
}
}
The problem is that requiring a JSON document creates an object instance, but returns a reference to that instance (objects are passed/assigned by reference). That means that when you assign myModel, which is a reference to the object to another variable, you are essentially assigning a pointer to that same object. Consequently, if you modify the reference, the single instance changes and that change reflects on all references to that instance.
Try something like this instead:
function _getModelInstance() {
return require('../../entities/myModel');
}
module.exports = {
find: function(id){
var myModelInstance1 = _getModelInstance();
myModelInstance1.id = 1;
var myModelInstance12 = _getModelInstance();
myModelInstance12.id = 2;
found.push(myModelInstance11);
found.push(myModelInstance12);
console.log("id: " + found[0].id);
}
This code will create a new instance of the object from the JSON document on demand.

creating one var object vs multiple var

For better code structure, I want to use a javascript object holding all properties instead of using multiple vars:
// 1. WAY
// This returns an error, as _inp cannot be accessed by input_value
// Uncaught TypeError: Cannot read property 'value' of undefined
var ref = {
_inp: input.target,
input_value: _inp.value,
....
};
// 2. WAY
// When using this, it works
var ref = {
_inp: input.target,
input_value: input.target.value,
....
};
// 3. WAY
// This obviously works, too.
var
_inp = input.target,
input_value = _inp.value,
My Question is, why does 3. Way works and 1.Way doesnt?
In example 1, _inp will be a property of an object. It isn't a variable. You can only access it from a reference to the object (and it won't be a property of the object until the object exists, which will be after the object literal has been evaluated, see also Self-references in object literal declarations).
Because _inp will only be filled in with the input.target value after passing through the entire var ref = { ... }; statement. This means that when you try to use it, it doesn't exist yet.
The 1st way don't work because you refers to "_inp" which is not an existing var. and the ref object is not fully created (that's why input_value: this._inp.value won't work either)
To create objects and assigning values to its properties, you can use a function (I keep most of your code):
var ref = {
_inp: input.target,
input_value: null,
init: function()
{
this.input_value = this._inp.value;
}
};
ref.init();
console.log(ref.input_value); // will contains the same as input.target.value
but usually, people create objects with all property with default values, and pass an argument to their init function:
var ref = {
_inp: null,
input_value: null,
init: function(input)
{
if (input)
{
this._inp = input.target;
this.input_value = input.target.value;
}
}
};
var input = {target:{value:"foo"}};
ref.init(input);

instantiating a javascript object from its name

I am kinda implementing my own very basic MVC controller and all I want is that if I have a viewName, I want to instantiate the javascript object with the name 'viewName'. for eg.
Lets say I have an object definition as
function ViewABC() {}
ViewABC.prototype.init = function() {
alert("comes here!");
};
now somewhere in my controller module, I get a view name as 'ViewABC'. All I want is to invoke the object with the viewName
function(viewName){
//check if viewName exists somewhere! initial validation
//create var viewObj = new 'viewName' here in this case it will be
//var viewObj =- new ViewABC();
//then call viewObj.init();
I looked into window[className] as well as this[className] but neither window or this has the function class that I have defined in the context.
Please advise.
Instead of just dumping functions in the global scope, what about this:
Views = Views || {}; // namespace initialization
Views['ViewABC'] = function() {};
// ...
var viewName = 'ViewABC';
var viewObj = new Views[viewName]();
UPDATE
Change the first line to:
window.Views = window.Views || {};
or if you only use it once, just:
Views = {};

Categories