Why Angular Input is undefined? - javascript

I have typical easy situation but in that case #Input() does not working...
Child Component:
#Component({
selector: 'app-test-grid',
templateUrl: './test-grid.component.html',
styleUrls: ['./test-grid.component.scss'],
})
export class TestGridComponent implements OnInit {
#Input() memos: any[];
constructor() {
console.log(this.memos); // prints undefined
}
ngOnInit() {
console.log(this.memos); // also prints undefined
}
}
<div *ngIf="checker()">
THIS IS DISPLAYED
<app-test-grid>
[memos]="test"
</app-test-grid>
</div>
// parent component.ts
test: number[] = [1, 2, 3, 4, 5, 6, 7];
ngOnInit() {
console.log(this.test); // print [1,2,3,4,5,6,7]
}
checker() {
console.log('checker', this.test.length !== 0); // this prints true
return this.test.length !== 0;
}
what's wrong with this code? this is very rudimentary case... I tried to found some another posts related but I didn't found answer.

You closed the app-test-grid tag so the memos assignment is lost as the content of the component. Use this:
<app-test-grid [memos]="test">
</app-test-grid>

Related

Return of toString() loses type after traversing the wire on HttpClient in Angular 10

I made a Foobar class with a toString() and it works well except when the Foobar is returned from a rest call. Below is the code and output. FOOBAR-1 works as expected, but FOOBAR-2 does not return a string, but an Object. Why? FOOBAR-3 returns as expected so it knows it's a Foobar.
app.component.ts
import { HttpClient } from '#angular/common/http';
import { Component, ViewChild } from '#angular/core';
import { Foobar } from './foobar';
import { Observable } from 'rxjs';
#Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
constructor(private http: HttpClient) {
}
ngAfterViewInit() {
console.log("FOOBAR-1 IS " + new Foobar().toString());
const remoteUrl:string = 'http://localhost:8080/foobar';
let observable:Observable<Foobar> = this.http.get<Foobar>(encodeURI(remoteUrl));
observable.subscribe(
(foobar: Foobar) => {
console.log("FOOBAR-2 IS "+foobar.toString());
console.log("FOOBAR-3 IS "+foobar.foo);
}
);
}
}
foobar.ts
export class Foobar {
foo:string ='bar';
toString(): string {
return this.foo;
};
}
Console output:
app.component.ts:18 FOOBAR-1 IS bar
app.component.ts:23 FOOBAR-2 IS [object Object]
app.component.ts:24 FOOBAR-3 IS bar
Is it possible to use a toString() on any object returned from HttpClient? What is happening here?
An HTTP call can only return strings, in your case likely the JSON string '{"foo": "bar"}'. That is unserialised into the Javascript object { foo: 'bar' }. That object behaves exactly as you're demonstrating:
const foobar = { foo: 'bar' };
console.log("FOOBAR-2 IS " + foobar.toString());
console.log("FOOBAR-3 IS " + foobar.foo);
It's not an instance of class Foobar, since you've never instantiated it as such. The HTTP client wouldn't know to do that. The type annotations just suggest that the returned object will behave like Foobar, they don't actually cast the type.

cannot read property of undefined angular 7

I am getting many errors at the dev tools console when adding a service into my component but the code still working but I want to get rid of from these errors
This's the service:
getPagesData(pageSlug: string): Observable<any[]> {
return this._http.get<any[]>(`${environment.apiUrl}wp/v2/pages/?slug=${pageSlug}`);
}
This is the component:
import { Component, OnInit } from '#angular/core';
import { DataService } from 'src/app/services/data.service';
#Component({
selector: 'app-membership',
templateUrl: './membership.page.html',
styleUrls: ['./membership.page.scss'],
})
export class MembershipPage implements OnInit {
public pageContent: any = {};
public content: string;
constructor(
private _data: DataService
) { }
ngOnInit() {
this._data.getPagesData('memberships')
.subscribe(
page => this.pageContent = page[0]
)
}
getContent(): string {
return this.pageContent.content.rendered.replace(/\[(.+?)\]/g, "");
}
}
What cause the errors is the getContent() method! it says that is the .rendered is an undefined property but it doses defined on the API!
I have searched on that problem and most of the solutions I found it's about using the symbol ? at HTML template but I can't use that in the component itself.
If you are calling getContent() in the HTML/template, you can most likely avoid this error by either:
Making pageContent initially null and using *ngIf to only display the content once it has asynchronously resolved:
Component:
public pageContent: any = null;
Template:
<div *ngIf="pageContent">{{getContent()}}</div>
Or you could instead RxJS operators such as map() and the async pipe:
Component:
import { Component, OnInit } from '#angular/core';
import { DataService } from 'src/app/services/data.service';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
#Component({
selector: 'app-membership',
templateUrl: './membership.page.html',
styleUrls: ['./membership.page.scss'],
})
export class MembershipPage implements OnInit {
public pageContent: Observable<string>;
public content: string;
constructor(private _data: DataService) { }
ngOnInit() {
this.pageContent = this._data.getPagesData('memberships')
.pipe(
map(page => page[0].content.rendered.replace(/\[(.+?)\]/g, ""))
);
}
}
Template:
<div>{{pageContent | async}}</div>
That being said, you should probably have additional checks to ensure each sub-property is available prior to accessing it, but usually this type of error is because you are attempting to access the contents before they have resolved.
Hopefully that helps!
Yes, you cannot use ? Elvis (Safe navigation) operator in the component itself because it is designed for view part only.
But you can add some check in the component too to avoid such errors like -
getContent(): string {
const dataToReturn = this.pageContent && this.pageContent.content && this.pageContent.content.rendered.replace(/\[(.+?)\]/g, "");
return dataToReturn
}
.rendered is an undefined property
Also, This error may produce you have defined pageContent = {} so on {} neither content nor rendered exist , may be that is also the reason to exist such errors.
Angular recommend to strongly typecast your data before use.

Destructuring objects in Javascript - ngbind - Angular 4+

Could someone tell me how to use destructured data in ng-bind in angular 4+?
I've come across how to use destructured object/array from here .
const wes = {
first: 'Wes',
last: 'Bos',
links: {
social: {
twitter: 'https://twitter.com/wesbos',
facebook: 'https://facebook.com/wesbos.developer',
},
web: {
blog: 'https://wesbos.com'
}
}
};
Trying to bind the data like below:
let {first : f, last:l} =wes;
In the html I simply used {{f}},
but it doesn't show anything. Did I understand wrongly ?
Please refer to what I did: stackblitz
Thanks all
You cannot directly use the object destructuring in angular, because it needs to be binded to the component directly.
Taking your sample, you can do something like this:
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
name = 'Angular 4';
count = 5;
_destructuring = '';
ngOnInit() {
const tmp = {a: 'hello'};
const {a: _destructuring} = tmp;
this._destructuring = _destructuring;
}
}
Updated example:
https://stackblitz.com/edit/angular-ngmodel-write-value-er4dcv?file=app/app.component.ts
Alternatively, you might want to use Object.assign on angular component's this. However, this would involve writing far much code than needed, so...
EDIT: as requested, here is the sample code with your original object, and the (working) example: https://stackblitz.com/edit/angular-ngmodel-write-value-lf97lr?file=app/app.component.ts
import { Component, OnInit } from '#angular/core';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
name = 'Angular 4';
count = 5;
_destructuring = '';
_nested = {};
ngOnInit() {
const tmp = {a: 'hello'};
const {a: _destructuring} = tmp
this._destructuring = _destructuring;
// Original (nested) object
const wes = {
first: 'Wes',
last: 'Bos',
links: {
social: {
twitter: 'https://twitter.com/wesbos',
facebook: 'https://facebook.com/wesbos.developer',
},
web: {
blog: 'https://wesbos.com'
}
}
};
// Object destructuring (links.social.facebook -> fb, links.social.twitter -> tw)
const {
links: {
social: {
facebook: fb,
twitter: tw
}
}
} = wes;
// Assign to the local property, available in the component.
Object.assign(this._nested, {
fb: fb,
tw: tw
});
}
}
Well seems to work great :
const person = {
first: 'John',
last: 'Doe',
};
const { first, last } = person;
const { first: f, last: l } = person;
console.log(first, last);
console.log(f, l);

Error with using Ngu Carousel with Angular 4

I am trying to use this carousel (https://github.com/sheikalthaf/ngu-carousel) with Angular 4 but I keep getting this error.
After having all imports in the App module and in the component, I have simplified the the code in the template to this and still error does not go away. Any ideas?
<ngu-carousel [inputs]="carouselOne" (carouselLoad)="myfunc($event)">
<ngu-item NguCarouselItem>
<div>--1--</div>
</ngu-item>
<ngu-item NguCarouselItem>
<div>--2--</div>
</ngu-item>
</ngu-carousel>
Below is the code in the component:
import { Component, OnInit } from '#angular/core';
import { NguCarousel, NguCarouselStore } from '#ngu/carousel';
import { Http } from '#angular/http';
import { FormGroup, FormBuilder } from '#angular/forms'
#Component({
selector: 'app-new-squad',
templateUrl: './new-squad.component.html',
styleUrls: ['./new-squad.component.css']
})
export class NewSquadComponent implements OnInit {
public carouselOne: NguCarousel;
public positions: Array<string> = [];
public players: Array<string> = [];
private form: FormGroup;
ngOnInit() {
console.log("here.........");
this.carouselOne = {
grid: {xs: 1, sm: 1, md: 1, lg: 1, all: 0},
slide: 1,
speed: 400,
interval: 4000,
point: {
visible: true
},
load: 2,
touch: true,
loop: true,
custom: 'banner'
}
}
onmoveFn(data: NguCarouselStore) {
console.log(data);
}
public myfunc(event: Event) {
// carouselLoad will trigger this funnction when your load value reaches
// it is helps to load the data by parts to increase the performance of the app
// must use feature to all carousel
}
public saveSquad(f) {
console.log(f.value);
this.http.post('http://localhost:8080/squads', f.value)
.subscribe(response => {
console.log(response);
})
}
}
Try adding these two buttons,
<button NguCarouselPrev class='leftRs'><</button>
<button NguCarouselNext class='rightRs'>></button>
Looking through the source code for ngu-carousel.component.ts there are several references to nativeElement in ngOnInit(). I'd say the following are most likely the cause the problem
this.rightBtn = this.next.nativeElement;
this.leftBtn = this.prev.nativeElement;
where this.next and this.prev are set by
#ContentChild(NguCarouselNextDirective, { read: ElementRef })
private next: ElementRef;
#ContentChild(NguCarouselPrevDirective, { read: ElementRef })
private prev: ElementRef;

How to check if two strings are almost equal with Angular

I have a quiz app made with Ionic and Angular 4. User have to submit answer, I check if it's the same as the good answer or not.
I would like to check string correspondence, and handle event according to the correspondence between good answer and user answer.
In Exemple :
If the answer is 'azerty', and he wrote 'mzerty', I would like to allow him to continue.
If user wrote 'qwerty', or something too different, he failes.
A simple demo with Levenstein distance would be like that:
Typescript
import { Component, OnInit } from '#angular/core';
import { FormBuilder, FormGroup } from '#angular/forms';
import { Observable } from 'rxjs/Observable';
import { map } from 'rxjs/operators';
import levenshtein from 'fast-levenshtein';
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit {
form: FormGroup;
score$: Observable<number>;
constructor(private fb: FormBuilder) { }
ngOnInit() {
this.initForm();
this.initScore();
}
private initForm() {
this.form = this.fb.group({
str1: '',
str2: '',
});
}
private initScore() {
this.score$ = this.form
.valueChanges
.pipe(
map(({str1, str2}) => levenshtein.get(str1, str2))
);
}
}
HTML
<form [formGroup]="form">
<input type="text" formControlName="str1">
<br>
<br>
<input type="text" formControlName="str2">
</form>
<br>
<div>
Levenshtein score: {{ score$ | async }}
</div>
Stackblitz live demo: https://stackblitz.com/edit/angular-usydyu
You can simply create a method which will return you how many characters are matched. so on basis of matched characters and the length of string you can decide weather its a good answer or not.
function checkEq(str1, str2){
var arr1 = str1.split('');
var arr2 = str2.split('');
var counter = 0;
for(var i=0;i<arr1.length;i++){
if(arr1[i]==arr2[i]){
counter++;
}
}
return counter;
}

Categories

Resources