Type 'CanDeactivate' is not generic - javascript

Following the Angular 2 example here. There is can error right after the implements while running tsc:
error TS2315: Type 'CanDeactivate' is not generic.
import { Injectable } from '#angular/core';
import { CanDeactivate } from '#angular/router';
import { Observable } from 'rxjs/Observable';
export interface CanComponentDeactivate {
canDeactivate: () => boolean | Observable<boolean>;
}
#Injectable()
export class CanDeactivateGuard implements CanDeactivate<CanComponentDeactivate> {
canDeactivate(component: CanComponentDeactivate): Observable<boolean> | boolean {
return component.canDeactivate ? component.canDeactivate() : true;
}
}
This is confusing to me, as the interface has already been declared. Why do I see an error there?

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.

Console Log objects when using console.info.bind(console)

I have seen many Angular2+ developers use the console.info.bind(console) method to make a logger service out of the javascript console logger. However, in my implementation of this, all of my javascript objects are logged out as [object object].
How can I tweak my logger so that my objects are rendered in my console?
ConsoleLogger.service.ts
import {Injectable} from '#angular/core';
import {environment} from '../../../environments/environment';
import {Logger} from './logger.service';
export let isDebugMode = environment.isDebugMode;
const noop = (): any => undefined;
#Injectable()
export class ConsoleLoggerService implements Logger {
get info() {
if (isDebugMode) {
return console.info.bind(console);
} else {
return noop;
}
}
get warn() {
if (isDebugMode) {
return console.warn.bind(console);
} else {
return noop;
}
}
}
Logger.Service.ts
import {Injectable} from '#angular/core';
export abstract class Logger {
info: any;
warn: any;
}
#Injectable()
export class LoggerService implements Logger {
info: any;
warn: any;
}
Example.Component.ts
import {Component, OnInit} from '#angular/core';
import {LoggerService} from 'src/app/core';
#Component({
selector: 'app-example-component',
templateUrl: 'example.component.html',
styles: ['example.component.scss']
})
export class ExampleComponent implements OnInit {
exampleObject: {a: 'apple'; b: 'banana'};
constructor(
private _logger: LoggerService,
) {
}
async ngOnInit() {
this._logger.info("Example Output: " + this.exampleObject);
// Example Output: [object object]
// ?? i want to see the actual object
}
}
If you want to see the Object in console, you should use JSON.stringify()
return console.info.bind(JSON.stringify(console));
After playing with this for awhile. I found out this gave me what I want.
this._logger.info('Example: ', this.exampleObject);

(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);
}));
}
}

having problems setting a member variable on an ng2 component

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;
}
}

Angular 2 Error: (SystemJS) Can't resolve all parameters for Member: (?).(…)

I use this seed application to narrow down an error that keeps popping up (so debugging is easier...)
I keep getting this error when trying to add a data model to my shared module (in my browser console):
Error: (SystemJS) Can't resolve all parameters for Member: (?).(…)
The Member Class in question:
import * as _ from 'lodash';
import { Injectable } from '#angular/core';
#Injectable()
export class Member {
private id: string;
[key: string]: any;
constructor(private data?: any) {
if (data) {
this.id = data.id;
_.extend(this, data.attributes);
}
}
}
My SharedModule (the Member Class isn't referenced anywhere else for now):
import { NgModule, ModuleWithProviders } from '#angular/core';
import { CommonModule } from '#angular/common';
import { FormsModule } from '#angular/forms';
import { RouterModule } from '#angular/router';
import { ToolbarComponent } from './toolbar/index';
import { NavbarComponent } from './navbar/index';
import { NameListService } from './name-list/index';
import { Member } from './models/member.model';
#NgModule({
imports: [CommonModule, RouterModule],
declarations: [ToolbarComponent, NavbarComponent],
exports: [ToolbarComponent, NavbarComponent,
CommonModule, FormsModule, RouterModule]
})
export class SharedModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: SharedModule,
providers: [NameListService, Member]
};
}
}
When I get rid of the constructor in class Member the error disappears:
import * as _ from 'lodash';
import { Injectable } from '#angular/core';
#Injectable()
export class Member {
private id: string;
[key: string]: any;
}
I am not using barrel imports as you can see since the order of the imports can cause the same error.
I am a bit stuck on how to solve this... Thanks
If the class is just to be used as a model, then don't add it to the #NgModule.providers and don't try to inject it. Just import the class into the class file where you need it, and just use it like you would any other normal class
import { Member } from './member.model';
#Component({})
class MyComponent {
member = new Member();
}
See Also:
Add Models/Entities/Objects to NgModule in Angular 2
Classes with the #Injectable() decorator get instantiated once by Angular as service providers. Angular uses reflection/type hinting to supply the instance with its dependency's.
Angular doesn't know what to give your Member class's constructor since its type is defined as any.

Categories

Resources