Angular: How to "Save" an "Object"? - javascript

Good Morning, I explain my scenario:
After generating a couple of http calls and after processing them I have a result similar to this:
xxx.component.ts
nameVariable: any = {};
this.nameVariable = this.createMyObject(params);
console.log(this.nameVariable);
Thanks to the console.log() we can see that is an Object: nameVariable like this:
Object: {
information1: Object {...},
information2: Array [...],
information3: Object{...},
information4: Array[...]
}
How can I save this Object??,
how do I Save it and then be able to use it within the code and/or use it within a Component??
Should use a Model?? what should I study to better understand this thing??

Your angular component is a class. The scope of your nameVariable variable is the body of the method where it is defined. You can extend the scope of that variable by introducing it as a field of your class before the constructor of the class as follows:
nameVariable: { (state here the type of the object };
and you may add a prefix like private or public just before the nameVariable word.
Refer to it as this.nameVariable afterwards inside the methods (the const keyword is no more required).

Related

How to access class attributes and functions within modules properly

I'm writing classes in ES6 modules using object literals and I want to set object attributes within a function. Now I know modules are executed in strict mode by default which makes usage of this safe or at least safer, but I'm not sure whether foo() modifies the object I'm accessing in the 'parent' script file or just the local object existing only in Controller.mjs. Do both function calls have the same effect?
//Controller.mjs
const Controller = {
someAttr1: [],
someAttr2: true,
foo: function () {
this.someAttr1.push("some value");
Controller.someAttr1.push("some value");
}
};
//export Controller's interface...
//SomeOtherFile.mjs
import { Controller } from 'Controller.mjs'
Controller.foo();
the object I'm accessing in the 'parent' script file or just the local object existing only in Controller.mjs
There is only a single object in your code. The import declaration really does nothing but create an alias for the const Controller variable in the imported module. There is no second object getting instantiated.
In general, for using this vs Controller to refer to the object, see Javascript: Object Literal reference in own key's function instead of 'this'. It doesn't matter whether the code is spread across modules or not for that.

Why use AngularJs .constant() if I can declare JS const?

I'm working on an AngularJS project where there is a .constant() provider to declare some basic information used across the whole project. For example, a definition of cookie name. Ex.:
.constant('appConst', {
cookie: 'CookieName',
...
});
But the same thing can be done by declaring a const, ex.:
const appConst = {
cookie: 'CookieName',
...
}
So, what is the advatage of using the .constant provider instead of just declaring a const? I know one of the reasons is because we don't expect the value to change. But isn't this the same objective of a const?
The new const keyword only makes it so you cannot reassign the variable, it doesn't make any object you initially assign to it immutable. So in your example with:
const appConst = {
cookie: 'CookieName',
...
}
You would still be able to change the value of cookie. You just wouldn't be allowed to do something like this:
appConst = { // My new object };
The values in the angular .constant() can also still be changed, so they're not constant in the common use of the word "constant". At least not when you use it like this:
.constant('appConst', {
cookie: 'CookieName',
...
});
So if you for instance do like this and change the value within a controller
app.controller('myController', function(appConst){
appConst.cookie = 'NewCookieName';
})
the change would be reflected anywhere you inject appConst after this controller was constructed.
You can't "reassign" appConst in this case though, that action would just be ignored, so it is constant in that sense.
1- const is new in ES6, so you may need to transpiler your code for supporting old browsers.
2- const is block-scoped, so within a scenario, you define a constant in A.js, will be not able to use it at B.js unless you're using a module bundler, so we went back to the topic 1-.
The main purpose of AngularJS having this native is to able you to share it between controllers, services, and directives, using its dependency injection system.

What to use for data-only objects in TypeScript: Class or Interface?

I have a bunch of data-only "classes" (in .NET world we call them POCO objects) that does not have any methods or even constructors. Examples are Customer, Product, User entities, you name it...
Originally I started using typescript classes but now I'm thinking that declaring them as interface might be better. From performance standpoint, and not only... It's just that in C# we're used to use interfaces for different thing, and for "POCO" (Plain-old-clr-object, or "data-only" object) we use just a class (sometimes even struct).
What is a proper way to declare them in TypeScript?
Note that I mostly understand (I think) technical differences between class and interface (i.e. that interface is a compile-time construct), but I'm trying to find out which one fits this case semantically.
P.S.: I've seen similar questions (like this) but none of them adress this specific issue clearly and definitely, so please don't close this as 'possible duplicate' or 'opinion-based' (cause it isn't) :)
Interface and it's not even close.
People start writing TypeScript and they suddenly think they have to use classes for some reason. But they don't. Classes are an ES6 feature and they work fine, but if it's just data, it's just data.
A major problem with using classes is that they won't serialize/deserialize like you expect over the wire, so things like instanceof checks won't work.
One rule of thumb is that if there's not internal state associated with some methods, and there's no need for traditional OO polymorphism, don't use a class. This even extends to static classes -- use namespace / module instead.
Use classes with parameter properties:
// Immutable data object
class Person {
constructor(readonly firstName: String, readonly lastName: String) {}
}
// Mutable data object
class Person {
constructor(public firstName: String, public lastName: String) {}
}
I use classes for my data in Typescript, as I allways did in C# C++ Java, and only use interfaces for dependency injection. Interfaces have not be thought for manipulating data.
In my application model, if I need to write a method that uses some datas of the same class, then the class is better place to go for that method. Adding getters and setters that transform your properties is a great flexibility.
I am not a javascript programmer so when I need to create an object, I don't like using data only object where properties can by anything. I create an instance of class by the way of the constructors that have been defined for that class.
When I receive data from a service, I don't deserialize a class: I deserialize the json data and I create my instance with that data. Here is the way for building my model from the received data:
// ajax callback for diaries
onReceiveDiary( jsonDiary : any )
{
let newDiary = new Diary ( jsonDiary );
// now I can call methods on the object:
let ok : boolean = newDiary.CheckIfCompleted();
}
In the class I add a constructor with the only one dependency on the json object:
export class Diary
{
title : string;
article : Article;
constructor( json : any )
{
// the trick for setting all the object properties
$.extend( this, json);
this.article = new Article( json.article );
}
}
Or we can create a factory for building objects using the default constructor:
let newDiary = new Diary ();
$.extend( newDiary, jsonDiary );
newDiary.article = $.extend( new Article(), jsonDiary.article );

Changing the scope (value of "this")

I'm trying to create a logger that outputs a message and the class it's called from, like this:
const __log = (...values: Array<any>) =>
console.log("%c" + this.constructor["name"], CLASS_STYLE, ...values);
This work nicely, but I'd like to keep it DRY, to import it once if possible and call wherever I need to. I was thinking about adding it as window.__log, but of course there's an issue with the scope of this.
What would be the best way to change the scope?
I'm looking for some kind of bind(), call(), apply() trickery/wizardry that would make this work (;
Example planker is here: http://plnkr.co/edit/sLdAsbv8FgO4V1qfqQZM (with Angular2 component). Removing the // const __log ... comment in class App would show what I want to get.
You can archive what you want by doing so:
function __log(...values: Array<any>)
{
console.log("%c" + arguments.callee.caller.name, CLASS_STYLE, ...values)
}
If you want to go deeper, here is some more info about getting full call stack: link

JavaScript variable scope - proper use

I read this style guide for angular from johnpapa. There is a snippet:
/*
* recommend
* Using function declarations
* and bindable members up top.
*/
function Avengers(dataservice, logger) {
var vm = this;
vm.avengers = [];
vm.getAvengers = getAvengers;
vm.title = 'Avengers';
activate();
function activate() {
return getAvengers().then(function() {
logger.info('Activated Avengers View');
});
}
function getAvengers() {
return dataservice.getAvengers().then(function(data) {
vm.avengers = data;
return vm.avengers;
});
}
}
So my question is in functions activate() and getAvengers(), they both reference variable (dataservice) and function (getAvengers()) outside of their scope. Is this proper use? Should I bind these 2 in the variable vm instead, e.g:
vm.getAvengers = getAvengers;
vm.dataservice = dataservice;
...
function activate() {
return vm.getAvengers().then(....);
}
function getAvengers() {
return vm.dataservice.getAvengers().then(.....);
}
Specifically for your case
Would say if you are meaning to use this within angular app would recommend not exposing the service, exposing it through this object does not add value and might down the road, when a less experienced developer modifies your code, might result in wonky access to shared dependencies.
If you want access to the dataservice objects functionality across multiple entities then register it as an angular service, and inject it to the different entities that need it.
In General
Both of the ways you are describing are perfectly correct use, but as is usually the case the answer which to use is "it depends."
Why you would use one for another would be if you wanted to expose the variable externally (i.e. if you wanted to let others access that object through the returned object, expecting others to dynamically change the service on your object)
So in this example you should ask yourself a few question
Do I want to expose this object through another object or do I want to let angular DI pass this along to the other controllers that need this functionality
Do I want to allow external entities to modify this object
Does exposing this service through my object make the use of the perceived use of this object more confusing?
But again for this particular case you should not expose it through your object ( through your variable vm, which is bound to the return object this, in this case )
The vm is a acronym for a view model (a object representation of your view) it is meant to be used within your view to bind elements, ui events to it. The dataservice and the logger seems to nothing to do with the view at all, they are just services used within a controller. If you assign them to the vm then you probably create a tightly coupling between your view and services thus it seems like a not a very good idea to me. You can think about the VM as a interface (glue) between your view and controller.
Here is a picture of the interactions between view model, controller, view and services.

Categories

Resources