having problems setting a member variable on an ng2 component - javascript

I'm having problems setting a member variable on an ng2 component. In the component below, I'm trying to set some service results to a member variable. updateSearchResults1() sets the member variable as expected but updateSearchResults2 delegates the promise to processSearchResults which returns the error: "TypeError: Cannot set property 'blogPostListItems' of null." My understanding was that these 2 implementations were functionally the same. So why can I set this.blogPostListItems from updateSearchResults1() whereas I get an error that this.blogPostListItems is null from updateSearchResults2()?
import { Component, OnInit, ViewChild, ElementRef } from '#angular/core';
import { Router } from '#angular/router';
import { BlogService } from '../../services/blog.service';
import { BlogLanding } from '../../entities/blog-landing';
import { Response } from '#angular/http';
#Component({
selector: 'blog-landing',
templateUrl: '../../../ng2/templates/blog-landing.component.html'
})
export class BlogLandingComponent implements OnInit
{
#ViewChild('ddlAuthor') ddlAuthor;
blogLanding: BlogLanding;
blogPostListItems: Array<Object>;
constructor(
private router: Router,
private blogService: BlogService){}
ngOnInit(): void
{
}
updateSearchResults1()
{
this.blogService
.getBlogPosts()
.then(blogPostListItems => this.blogPostListItems = blogPostListItems)
}
updateSearchResults2()
{
this.blogService
.getBlogPosts()
.then(this.processSearchResults);
}
processSearchResults(responseObject)
{
this.blogPostListItems = responseObject;
}
}

Related

expression has changed after it was checked in loading component

I have repetitive problem in angular but I had search a lot about this problem and use all of Technics that answer in stackoverflow and... .
my problem is in my loader component when I subscribe over than one.
this is my loader component
import { Component, ChangeDetectionStrategy, ChangeDetectorRef, DoCheck, OnChanges, AfterViewInit, OnInit } from '#angular/core';
import { Subject, BehaviorSubject } from 'rxjs';
import { LoaderService } from './loader.service';
#Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'app-loader',
templateUrl: './loader.component.html',
styleUrls: ['./loader.component.scss']
})
export class LoaderComponent implements OnInit {
isLoading: BehaviorSubject<boolean>=this.loaderService.isLoading;
constructor(private loaderService: LoaderService, private changeDetector: ChangeDetectorRef) {
}
color = 'accent';
mode = 'indeterminate';
value = 50;
ngOnInit(): void {
}
}
and this is my service loader component
import { BehaviorSubject } from 'rxjs/internal/BehaviorSubject';
import { Injectable } from '#angular/core';
import { Subject } from 'rxjs';
#Injectable({
providedIn: 'root'
})
export class LoaderService {
constructor() { }
isLoading: BehaviorSubject<boolean> = new BehaviorSubject(false);
count=0;
show(): void {
debugger
console.log(`show`+this.count++)
this.isLoading.next(true);
}
hide(): void {
debugger
console.log(`hide`+this.count++)
this.isLoading.next(false);
}
}
and this is my interceptor loader
import { Injectable } from '#angular/core';
import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '#angular/common/http';
import { Observable } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { LoaderService } from './loader/loader.service';
#Injectable()
export class LoaderInterceptor implements HttpInterceptor {
constructor(public loaderService: LoaderService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
this.loaderService.show();
return next.handle(req).pipe(
finalize(() => {this.loaderService.hide(); })
);
}
}
my error message is
"
ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: 'ngIf: [object Object]'. Current value: 'ngIf: true'.
at viewDebugError (core.js:17871)
at expressionChangedAfterItHasBeenCheckedError (core.js:17859)
at checkBindingNoChanges (core.js:18059)
at checkNoChangesNodeInline (core.js:27635)
at checkNoChangesNode (core.js:27624)
at debugCheckNoChangesNode (core.js:28228)
at debugCheckDirectivesFn (core.js:28156)
at Object.updateDirectives (loader.component.html:2)
at Object.debugUpdateDirectives [as updateDirectives] (core.js:28145)
at checkNoChangesView ("
please help me to solve it.it's my big problem :-(
I was changing "behavior subject" to observable. subscribe data in loading page and used angular change detector in life cycle.Now, the problem is solve and work correctly
I'm not exactly sure where the 'ngIf' statement is being used, but an alternative might be instead to use css to hide the loader when not in use. E.g.
<div #myLoader [style.display]="isLoading ? 'block' : 'none'>...
To avoid it put a default value for your isLoading property (false for example), and wait the ngOnInit or ngAfterViewInit to change the property in the component.
Tried to replicate your code in a standalone stackblitz instance https://stackblitz.com/edit/angular-multisub with multiple subscriptions for loaderService.
Works without any problem.
Could you fork the above instance and modify to reproduce the same.

What's the correct way to load and open a component inside a modal dialog in Angular4 --

I have a component called NewCustomerComponent and I want to load and display it through a modal popup in another page/component when a button is clicked. I have written the relevant bit of code [or so it seems]. But I am getting the following error --
this._childInstance.dialogInit is not a function
at ModalDialogComponent.dialogInit (modal-dialog.component.js:65)
at ModalDialogService.openDialog (modal-dialog.service.js:26)
at OrderNewComponent.newCl (order-new.component.ts:85)
My code is pretty simple too, in the component where I am trying to open the modal popup.
I'll just post the relevant portions --
import { Component, Inject, ViewContainerRef, ComponentRef } from
'#angular/core';
import { Http, Headers } from '#angular/http';
import { Router } from '#angular/router';
import { Observable, Subject } from 'rxjs';
import 'rxjs/add/operator/map';
import { CustomerSearchService } from '../../../shared/services/customer-
search.service';
import { ICustomer, Customer, CustomerD } from
'../../../shared/models/customer';
import { ModalDialogModule, ModalDialogService, IModalDialog } from 'ngx-
modal-dialog';
import { NewCustomerComponent } from
'../../../components/popups/customer/customer-new.component';
#Component({
selector: 'order-new',
templateUrl: './order-new.component.html'
})
export class OrderNewComponent {
public reference: ComponentRef<IModalDialog>;
constructor(private cusService: CustomerSearchService, private http:
Http, private modalService: ModalDialogService, private viewRef:
ViewContainerRef) {
}
ngOnInit(): void {
}
** this is where I am trying to load the newcustomercomponent and open it
in the popup. not working.
newCl() {
this.newC = true;
this.exiC = false;
this.modalService.openDialog(this.viewRef, {
title: 'Add New Customer',
childComponent: NewCustomerComponent
});
}
}
** edits. NewCustomerComponent code added for reference.
import { Component, Input, Output, EventEmitter, OnInit,
ChangeDetectorRef, Directive, ElementRef, Renderer, AfterViewInit }
from '#angular/core';
import { Router, ActivatedRoute } from '#angular/router';
import { NgFor } from '#angular/common';
import { Observable } from 'rxjs/Rx';
import { BehaviorSubject } from 'rxjs/Rx';
import { PlatformLocation } from '#angular/common';
import { Http } from '#angular/http';
import { ICustomer, Customer } from '../../../shared/models/customer';
import { UserService } from '../../../shared/services/UserService';
import { IModalDialog, IModalDialogOptions, IModalDialogButton } from
'ngx-modal-dialog';
#Component({
selector: 'new-customer',
templateUrl: './customer-new.component.html'
})
export class NewCustomerComponent implements IModalDialog {
model: Customer = new Customer();
errors: any;
submitResponse: any;
actionButtons: IModalDialogButton[];
constructor(private userService: UserService, private http: Http) {
this.actionButtons = [
{ text: 'Close', onAction: () => true }
];
}
ngOnInit() {
}
dialogInit(reference: ComponentRef<IModalDialog>, options:
Partial<IModalDialogOptions<any>>)
{
// no processing needed
}
createCustomer() {
this.userService.createCustomer(this.model)
.take(1)
.subscribe(
(response: any) => {
this.submitResponse = response;
if (response.success) {
console.log('New customer added!');
}
else {
console.log('Unable to add customer!');
}
},
(errors: any) => this.errors = errors
);
return false;
}
cancelClicked() {
}
}
What did I do wrong here? Has it got something to do with the element reference I added in terms of the viewRef? Which portion is erroneous? What about that child component? Does it require to have some specific configuration/markup/component for this to work? I am very new to angular; I am not sure whatever the reason is.
Kindly help me rectify this scenario.
Thanks in advance,
Can you please ensure that the NewCustomerComponent is implementing the IModalDialoginterface. Also, if this is not the case can you please share the code of NewCustomerComponent as well.
edits
Looks like you have not defined the dialogInit method in the NewCustomerComponent and it didn't pop up before as you have not implemented the interface IModalDialog. I would request you to define the dialogInit method in the component class as suggested on the link.

Storing and accessing a global flag/variable in each component, The value keeps changing

I am trying to make a global service class which will store few variables which will influence behaviour on HTML components base on flags.
My current only flag is a BehaviourSubject which navbar component subscribes to update a navbar with different buttons. The issue is when I refresh the page in a browser the flag reverse to the original value and forgets what has set before. The current scenario is when user log in the flag is being set to true and should stay true until a user logs out. It may not be a right way to do it so if there is a better way of approaching it; then I am happy to implement it.
Data sharing class:
import {
Injectable
} from '#angular/core';
import {
BehaviorSubject
} from 'rxjs';
#Injectable()
export class ServiceClassDatasharing {
public isUserLoggedIn: BehaviorSubject < boolean > = new BehaviorSubject < boolean > (false);
public setUserLoggedInStatus(status) {
this.isUserLoggedIn.next(status);
}
}
Nav Component:
import {
Component,
OnInit
} from '#angular/core';
import {
MatDialog,
MatDialogRef,
MAT_DIALOG_DATA
} from '#angular/material';
import {
Inject
} from '#angular/core';
import {
ServiceClassDatasharing
} from '../service/service-class-datasharing';
import {
ServiceClassAuth
} from '../service/service-class-auth';
import {
SigninComponent
} from './../signin/signin.component';
import {
Router
} from '#angular/router';
#Component({
selector: 'app-nav',
templateUrl: './nav.component.html',
styleUrls: ['./nav.component.css']
})
export class NavComponent implements OnInit {
id_token: Boolean;
username: String;
constructor(public dialog: MatDialog, private dataSharingService: ServiceClassDatasharing,
private authService: ServiceClassAuth, private router: Router) {
this.dataSharingService.isUserLoggedIn.subscribe(res => {
this.id_token = res;
if (this.id_token) {
const user = JSON.parse(localStorage.getItem('user'));
this.username = user['user'].user_username;
}
});
if (!this.id_token) {
router.navigate(['index']);
}
}
ngOnInit() {}
openDialog(): void {
let dialogRef = this.dialog.open(SigninComponent, {
width: '450px',
data: {}
});
}
public logout() {
this.authService.logout().subscribe(res => {
if (res['success']) {
localStorage.clear();
this.dataSharingService.setUserLoggedInStatus(false);
}
});
this.router.navigate(['index']);
}
}
Index Component as an example it should redirect a user to dashboard if the global flag is set to true.
import {
Component,
OnInit
} from '#angular/core';
import {
ServiceClassDatasharing
} from '../service/service-class-datasharing';
import {
Router
} from '#angular/router';
#Component({
selector: 'app-index',
templateUrl: './index.component.html',
styleUrls: ['./index.component.css']
})
export class IndexComponent implements OnInit {
constructor(private dataSharingService: ServiceClassDatasharing, private router: Router) {
if (this.dataSharingService.isUserLoggedIn.value) {
this.router.navigate(['dashboard']);
}
}
ngOnInit() {}
}
Try using localStorage variable to achieve the same .
Create a function in service class which will set the variable with token if user logs in and function to get the same token.
const key = 'abcde'
setUseLoggedIn(token){
localStorage.setItem(this.key,token);
}
getUserLoggedIn(){
return localStorage.getItem(this.key);
}
set token as null if user is not logged in and check for the same when retrieving the token.

data not accessible outside of subscription function

I am passing data between components onload. When the component receives the information within the subscribe function it is able to use the data and do whatever with it, so a console.log works fine, so it is clearly receiving it, but immediately outside of the subscribe function the information is unaccessible and is undefined. So I can't run a console.log or do anything with the information. In the html, it says that it is undefined as well.
The component.
import { Observable } from 'rxjs/Rx';
import { User } from '../User';
import { AccountInfo } from './../AccountInfo';
import { LoginService } from './../login.service';
import { Component, OnInit, AfterViewInit, OnDestroy, ElementRef, ViewChild } from '#angular/core';
import {ActivatedRoute} from '#angular/router';
import { Subscription } from 'rxjs/Subscription';
import 'rxjs/add/operator/map';
#Component({
selector: 'app-dashboard',
templateUrl: './dashboard.component.html',
styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit, AfterViewInit {
public user: User;
public subscription: Subscription;
constructor(route: ActivatedRoute, private loginService: LoginService) {}
ngOnInit() {
this.loginService.getMessage().subscribe(data =>
{
this.user = data;
console.log(this.user.vendorname);
});
console.log(this.user.vendorname);
}
ngAfterViewInit() {
//Called after ngAfterContentInit when the component's view has been initialized. Applies to components only.
//Add 'implements AfterViewInit' to the class.
}
}
relevant section of html
<h1>Welcome {{user.vendorname}}</h1>
Yes.. that's how async functions work. The thing you pass into the subscribe function is another function.
data => {
this.user = data;
console.log(this.user.vendorname);
}
This will be called once the getMessage() has received answer from your server. Any statements after the subscribe will be called immediately, and that's why this.user.vendorname is still undefined when you try to log it there.
If you are receiving an error in your html you should use the safe navigation operator (?.):
<h1>Welcome {{user?.vendorname}}</h1>

(Angular2) JSON data (http.get()) is undefined, and data is not updated in the component

My http-data.service accepts json for output in the component template. Initially, the console shows that the first few calls are given undefined, and the following calls are already taking json, but also if you check the component, then the component shows that the method that outputs the data to the component is called only once and since the data has not yet arrived it writes undefined , But not updated after the arrival of json. Help please understand why? Thank you
My http-data.service:
import {Injectable} from '#angular/core';
import {Http} from '#angular/http';
import {Response} from '#angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
#Injectable()
export class HttpService{
constructor(private http: Http) {}
getDataOrganizations(): Observable<any[]>{
return this.http.get('http://localhost:3010/data')
.map((resp:Response)=>{
let dataOrganizations = resp.json().organization;
return dataOrganizations;
});
}
getDataModules(): Observable<any[]> {
return this.http.get('http://localhost:3010/data')
.map((resp: Response)=> {
let dataModules = resp.json().modules;
return dataModules;
});
}
getDataPresets(): Observable<any[]> {
return this.http.get('http://localhost:3010/data')
.map((resp: Response)=> {
let dataPresets = resp.json().presets;
return dataPresets;
});
}
getDataModuleItems(): Observable<any[]> {
return this.http.get('http://localhost:3010/data')
.map((resp: Response)=> {
let dataModuleItems = resp.json().module_items;
return dataModuleItems;
});
}
}
My data-all.service
import { Injectable, EventEmitter } from '#angular/core';
import {Response} from '#angular/http';
import { ModuleModel } from './model-module';
import { ModuleItemsModel } from './model-module-items';
import data from '../data/data-all';
import { PriceService } from './price.service';
import { HttpService } from './http-data.service';
#Injectable()
export class ModuleDataService {
constructor(private priceService: PriceService, private httpService: HttpService){
this.dataMinMaxSum = {minSum: 0, maxSum: 0}
}
private currentPopupView: EventEmitter<any> = new EventEmitter<any>();
private dataModules: ModuleModel[] = this.getDataModules();
private dataMinMaxSum: {};
private dataCalculateVariationOrg: any[];
private dataChangeExecutor: any[];
subscribe(generatorOrNext?: any, error?: any, complete?: any) {
this.currentPopupView.subscribe(generatorOrNext, error, complete);
}
calculte(){
return this.priceService.getDataPrice();
}
getDataModules(){
this.httpService.getDataModules().subscribe(((modules)=>{this.dataModules = modules; console.log(this.dataModules);}));
console.log('dataModules');
console.log(this.dataModules);
return this.dataModules;
}
---------------------------------------------------------------------------
}
My left-block.component
import { Component, OnInit} from '#angular/core';
import { ModuleDataService } from '../../service/data-all.service';
import { ModuleModel } from '../../service/model-module';
#Component({
moduleId: module.id,
selector: 'modules-left-block',
templateUrl: './modules-left-block.html',
styleUrls: ['modules-left-block.css']
})
export class ModuleLeft implements OnInit{
modules: ModuleModel[];
constructor(private modulesAll: ModuleDataService){}
ngOnInit(){
this.modules = this.modulesAll.getDataModules();
console.log("view");
console.log(this.modulesAll.getDataModules());
}
onToggle(module: any){
this.modulesAll.toggleModules(module);
}
}
My left-block.component.html
<div class="modules-all">
<div class="modules-all-title">Все модули</div>
<div class="module-item" *ngFor="let module of modules" [ngClass]="{ 'active': module.completed }" (click)="onToggle(module)">{{module?.title}}</div>
</div>
In the component this.modulesAll.getDataModules () method is why it is executed only once without updating (write in console => undefined), if there are any thoughts, write, thanks.
This behaviour is due to the .subscribe() method does not wait for the data to arrive and I'm guessing you already know this. The problem you're facing is because, you have .subscribe to the getDataModules() service in the wron place. You shouldn't subscribe to a service in another service (at leat in this case). Move the subscribe method to the left-block.component and it should work.
getDataModules() {
this.httpService.getDataModules().subscribe(((modules) => {
this.dataModules = modules;
console.log(this.dataModules);
}));
console.log('dataModules');
console.log(this.dataModules);
return this.dataModules;
}
It should look somethig like this:
#Component({
moduleId: module.id,
selector: 'modules-left-block',
templateUrl: './modules-left-block.html',
styleUrls: ['modules-left-block.css']
})
export class ModuleLeft implements OnInit {
modules: ModuleModel[] = new ModuleModel();
constructor(private modulesAll: ModuleDataService, private httpService: HttpService) {}
ngOnInit() {
this.getDataModles();
//this.modules = this.modulesAll.getDataModules();
console.log("view");
//console.log(this.modulesAll.getDataModules());
}
onToggle(module: any) {
this.modulesAll.toggleModules(module);
}
getDataModules(): void {
this.httpService.getDataModules().subscribe(((modules) => {
this.modules = modules;
console.log(this.dataModules);
}));
}
}

Categories

Resources