I need to know which is executed first in the component and execution order.
Get is called before constructor or Constructor gets called first. I am unable to put console in Get accessor.
export class AppComponent implements OnChanges {
title = 'app';
constructor() {
console.log('constructor called on App Component');
}
ngOnChanges() {
console.log(' onChanges called on App Component');
}
clicked() {
console.log('red');
}
get name(): string {
return 'sahir';
console.log('called get method');
}
}
The constructor will always be called first. You need an instance of the class in order to access a property.
Also, the console.log you put on the getter will never run since it is after a return statement.
Related
export class AppComponent {
title = 'my-app';
constructor(private notifyService : NotificationService) {}
ngOnInit() {
socket.on("laravel_database_chat:test", function(message){
//I WANT TO CALL NOTIFICATION SERVICE HERE, BUT NOT WORKING
this.notifyService.showSuccess();
});
I am trying to call notification service inside socket.io class, but not working.
Change normal function to arrow function to get access to this outside current scope.
ngOnInit() {
socket.on("laravel_database_chat:test", (message) => {
this.notifyService.showSuccess();
});
}
I have a service that connects with api
export class ConsolidadoApi {
constructor(private http: HttpClient) { }
getInvestiments(search?: any): Observable<any> {
return this.http.get<any>(`${environment.basePosicaoConsolidada}`);
}
}
Response this api:
https://demo5095413.mockable.io/consolidado
This one is responsible for the logic before reaching the component
#Injectable({
providedIn: 'root'
})
export class CoreService {
public test;
constructor(private api: ConsolidadoApi, private state: StateService) { }
public createMenu() {
this.api.getInvestiments()
.subscribe(response => {
console.log(response.carteiras[0])
this.products = response.carteiras[0]
return this.products;
})
}
In my component
export class MenuComponent implements OnInit {
constructor( private coreService : CoreService ) {}
ngOnInit(): void {
console.log(this.coreService.createMenu())
}
}
But when createMenu is called in menu.component.ts it comes undefined.
The raw response is an object. forEach works only on an array. If you are aiming for forEach in 'categorias', you should try
this.test.categorias.forEach()
When you return Observable<any>, that means the argument of the lambda you create when you do subscribe (which you named response) is type any. This doesn't necessary have the function forEach defined (unless the API returns an object with that prototype). That's generally why using any is not good practice; you can't have any expectations on what the object can contain. In fact, it's possible that it's not on object (it could be an array since any is not exclusively an object). If you do want to use forEach, you will want to make sure that response is type array. You can inspect the object's type before using it (e.g. using typeof) and make a judgement on what to call or even just check if the function you're trying to use is defined first, e.g. if (response.forEach !== undefined). You don't actually need to compare to undefined though, so if (response.forEach) suffices. In the examples, I used response, but you can use this.test since they are the same object after the first line in the lambda.
Based on the link you shared, the response is an object. You can log it to the console to confirm.
You can only call for each on an array, so for example, based on the response api, you can call forEach on the property ‘categorias’ and on that array’s children property ‘produtus’
Edit: this answer was based on the op original api and question
https://demo5095413.mockable.io/carteira-investimentos
public createMenu() {
return this.api.getInvestiments()
}
ngOnit() {
this.coreService.createMenu().subscribe(x => console.log(x.categorias))};
{
"codigo":1,
"categorias":[
{
"nome":"Referenciado",
"valorTotal":23000.0,
"codigo":"2",
"produtos":[
{
"nome":"CDB Fácil Bradesco",
"valor":2000.0,
"codigo":1,
"quantidade":0.0,
"porcentagem":0.5500,
"aplicacaoAdicional":500.0,
"codigoInvest":1,
"salaInvestimento":"CDB",
"permiteAplicar":true,
"permiteResgatar":true,
"movimentacaoAutomatica":false,
"ordemApresentacao":37,
"horarioAbertura":"08:30",
"horarioFechamento":"23:59",
"codigoGrupo":0,
"codigoMF":"001
I have a callback function which returns some data to the component.
export class AppComponent {
constructor(
private service: AppService
) {
this.processSomething(true);
this.processSomething(false);
}
private processSomething(isZoom: boolean = false) {
this.service.handleAsyncResponses(
this,
this.processDataReceived
);
}
private processDataReceived(
attributeValueList: any,
isZoom?: boolean
) {
console.log("isZoom:", isZoom);
}
}
I need to send some value isZoom parameter from the component and access the same in console.log("isZoom:", isZoom). Now console.log is loggin undefined.
A working sample is here: https://stackblitz.com/edit/angular-service-oqkfmf?file=app/app.component.ts
I think you're getting a little lost.
I took the freedom to clean your stackblitz from non-used code and show you how to use callbacks : you can check it there.
Let's start with the component :
constructor(
private service: AppService
) {
this.processSomething(true);
this.processSomething(false);
}
private processSomething(isZoom: boolean = false) {
this.service.handleAsyncResponses(isZoom, this.processDataReceived);
}
private processDataReceived(isZoom: boolean) {
console.log("isZoom:", isZoom);
}
You don't need to define your parameters as optional, since you give your isZoom value a default value, hence making it always defined.
As you can see, you don't need to pass your full object as an argument : the function can be called without it.
In your service, all you have left is
public handleAsyncResponses(zoom: boolean, callback: Function) {
callback(zoom);
}
Simply call the function as you would in any other context. simply rename this.processDataReceived(zoom) with the name of the parameter (here it being callback).
This is how callbacks are handled.
In your case, you need to wrap the function call in local closure:
private processSomething(isZoom: boolean = false) {
this.service.handleAsyncResponses(
this, (attributeValueList: any) => {
this.processDataReceived(attributeValueList, isZoom);
}
);
}
changed example
I'm learning Angular 2. And got confused over constructor.
Consider the below code :
import { Component, OnInit } from '#angular/core';
import { FormGroup,FormsModule,FormControl } from '#angular/forms';
import { WeatherService } from '../weather.service';
import { WeatherItem } from '../weather-item';
#Component({
selector: 'app-weather-search',
templateUrl: './weather-search.component.html',
styleUrls: ['../../assets/app.css'],
//providers: [WeatherService]
})
export class WeatherSearchComponent implements OnInit {
constructor(private _weatherService : WeatherService) { }
onSubmit(form : FormGroup){
//alert(form.value.location);
this._weatherService.searchWeatherData(form.value.location)
.subscribe(
data => {
const weatherItem = new WeatherItem(data.data.request["0"].query,data.data.weather["0"].maxtempC,data.data.weather["0"].maxtempC);
this._weatherService.addWeatherItems(weatherItem);
console.log(form);
})
}
ngOnInit() {
}
}
Here we are injecting 'WeatherService' in constructor. Can't we do the same outside constructor ? What constructor is doing here actually? Do we really need it here?
The constructor itself is not doing actual work.
Angular creates a new WeatherSearchComponent executing
new WeatherSearchComponent(weatherService);
and this causes the constructor in WeatherSearchComponent to receive the weatherService value.
The constructor
constructor(private _weatherService : WeatherService)
causes an instance field _weatherService to be created and initialized with the value passed from DI.
The constructor is the only place where it is easy to know when the injected service is available and when not.
If the service would passed to a field, setter or method, code in the constructor could not access it because the constructor is executed before outside code has a change to set a field or call a method.
Also for code outside the constructor it is not safe to assume the service is available because this code could be called from the constructor before a field could be set from the outside.
For dependency injection passing dependencies to the constructor is the only way to avoid a lot of complexity.
Dependency Injection in constructor is always better option and while the component is getting created it will get the weatherService as a parameter. To make it clear, below is the transpiled code for your snippet.
var WeatherSearchComponent = (function () {
function WeatherSearchComponent(_weatherService) {
this._weatherService = _weatherService;
}
WeatherSearchComponent.prototype.onSubmit = function (form) {
var _this = this;
//alert(form.value.location);
this._weatherService.searchWeatherData(form.value.location)
.subscribe(function (data) {
var weatherItem = new weather_item_1.WeatherItem(data.data.request["0"].query, data.data.weather["0"].maxtempC, data.data.weather["0"].maxtempC);
_this._weatherService.addWeatherItems(weatherItem);
console.log(form);
});
};
WeatherSearchComponent.prototype.ngOnInit = function () {
};
WeatherSearchComponent = __decorate([
core_1.Component({
selector: 'app-weather-search',
templateUrl: './weather-search.component.html',
styleUrls: ['../../assets/app.css'],
})
], WeatherSearchComponent);
return WeatherSearchComponent;
}());
exports.WeatherSearchComponent = WeatherSearchComponent;
As you can see in turn the javascript code has weatherService Instance being passed on to the function weatherSearchComponent.
I'm trying to make a website where i use Aurelia and Javascript and ES6.
I have a simple class (Status) that needs to get some data on a interval from a server.
Update
I have added CalcData to the injector as sugessted by Fabio Luz, but i still get the same error. Good call btw ;).
The class looks like this:
import {inject} from "aurelia-framework"; // for the inject decorator
import { StatusData } from "./statusData"; // MovieData, the module that will be injected
import { CalcData } from "./Calc"
#inject(StatusData, CalcData) // Inject decorator injects MovieData
export class Status {
constructor(StatusData, CalcData) {
this.statusData2 = StatusData;
this.CalcData = CalcData;
}
activate() {
setInterval(this.updateCalc, 3000);
}
updateCalc() {
this.CalcData.hello()
.then(statusData => this.statusData2 = statusData);
}
updateStatus() {
return statusData2.getX()
.then(statusData => this.statusData2 = statusData);
}
update() {
return 1;
}
}
The updateCalc function is called but when this happens the browser says it that CalcData is undefined.
Uncaught TypeError: Cannot read property 'hello' of undefined
at updateCalc (status.js:17)
updateCalc # status.js:17
status.js:17 Uncaught TypeError: Cannot read property 'hello' of undefined
at updateCalc (status.js:17)
updateCalc # status.js:17
The CalcData class looks like this:
import { inject } from "aurelia-framework"; // for the inject decorator
import { HttpClient } from "aurelia-http-client"; // for the http client that will be injected
let baseUrl = "/movies.json";
#inject(HttpClient)
export class CalcData {
constructor(httpClient) {
this.http = httpClient;
}
hello() {
return this.http.get(baseUrl)
.then(response => {
return response.content;
});
}
}
I can't seem to find the problem, i have looked around but can't find a solution. I must say that i'm new to Aurelia.
Any help is much appreciated!
Your problem is down to capitalization, most likely.
Let's look at the beginning of your code:
import {inject} from "aurelia-framework"; // for the inject decorator
import { StatusData } from "./statusData"; // MovieData, the module that will be injected
import { CalcData } from "./Calc"
#inject(StatusData, CalcData) // Inject decorator injects MovieData
export class Status {
constructor(StatusData, CalcData) {
this.statusData2 = StatusData;
this.CalcData = CalcData;
}
Notice that your constructor is taking parameters whose names exactly match the names of the classes you want to inject. This is causing confusion for the runtime, as you are likely ending up setting this.Calcdata to the class CalcData (and the same for StatusData). The class does not have a function called hello(), only instances of the class have that function. If you change the parameter names to not exactly match, your issues should go away.
#inject(StatusData, CalcData) // Inject decorator injects MovieData
export class Status {
constructor(statusData, calcData) {
this.statusData = statusData;
this.calcData = calcData;
}
I've also lower-cased the property names to match JavaScript naming conventions.
Seems like i had to bind "this" to pass the object reference. When calling this in hello it how read gets the right object.
E.g.
import {inject} from "aurelia-framework";
import {StatusService} from "./statusService"
#inject(StatusService)
export class Status{
message = 'unknown yet';
statusService: StatusService;
constructor(statusService){
this.statusService = statusService;
}
activate(){
setInterval(this.updateStatus.bind(this), 3000);
}
updateStatus = function () {
this.message = this.statusService.getX();
}
}