New to Typescript/Angular. TS2339 compiling error. *ngIf="x.length > 0;" should be false but still tries to compile the elements inside - html

I'm following a Typescript/Angular course that is showing me how to use "*ngIf". The instructor is giving an example of an empty array so that it fails the condition and compiles the second set of ul tags. It worked for the instructor, but not for me.
image-box.component.html
<div id="image-box">
<div class="left">
<img src="https://images.unsplash.com/photo-1606857521015-7f9fcf423740?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1740&q=80"/>
<app-title></app-title>
</div>
<div class="right">
<h3>Contracts</h3>
<ul *ngIf="contractInComponent.length > 0">
<li *ngFor="let contract of contractInComponent">
Service: {{ contract.service }} <br>
Title: {{ contract.title }}
</li>
</ul>
<ul *ngIf="contractInComponent.length == 0">
<li>Empty</li>
</ul>
</div>
</div>
get-data.service.ts
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class GetDataService {
constructor() { }
getContracts() {
return [];
}
}
image-box.component.ts
import { Component, OnInit } from '#angular/core';
//import { ImageBoxService } from './image-box.service';
import { GetDataService } from './get-data.service';
#Component({
selector: 'app-image-box',
templateUrl: './image-box.component.html',
styleUrls: ['./image-box.component.scss']
})
export class ImageBoxComponent implements OnInit {
contractInComponent;
constructor(service:
GetDataService) {
this.contractInComponent = service.getContracts();
}
ngOnInit() {}
}
Compiled with problems:
ERROR
src/app/image-box/image-box.component.html:12:38 - error TS2339: Property 'service' does not exist on type 'never'.
12 Service: {{ contract.service }} <br>
~~~~~~~
src/app/image-box/image-box.component.ts:7:16
7 templateUrl: './image-box.component.html',
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Error occurs in the template of component ImageBoxComponent.
ERROR
src/app/image-box/image-box.component.html:13:36 - error TS2339: Property 'title' does not exist on type 'never'.
13 Title: {{ contract.title }}
~~~~~
src/app/image-box/image-box.component.ts:7:16
7 templateUrl: './image-box.component.html',
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Error occurs in the template of component ImageBoxComponent.
This works when I explicitly use Booleans. The first ul tag gets ignored and compiles the second set. The output is 0.
image-box.component.html
<div id="image-box">
<div class="left">
<!-- <h2>{{ contractInComponent[0].service }}</h2> -->
<img src="https://images.unsplash.com/photo-1606857521015-7f9fcf423740?ixlib=rb-4.0.3&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1740&q=80"/>
<app-title></app-title>
</div>
<div class="right">
<h3>Contracts</h3>
<ul *ngIf="false">
<li *ngFor="let contract of contractInComponent">
Service: {{ contract.service }} <br>
Title: {{ contract.title }}
</li>
</ul>
<ul *ngIf="true">
<li>{{ contractInComponent.length }}</li> <!-- output = 0 -->
</ul>
</div>
</div>
get-data.service.ts
import { Injectable } from '#angular/core';
#Injectable({
providedIn: 'root'
})
export class GetDataService {
constructor() { }
getContracts() {
return [];
}
}

Your compiler automatically determines a return type and sees that your getContracts() is always returning undefined. That's why you have the error. If you explicitly add a return type like this.
getContracts() : any {
return [];
}
The error will disappear because you tell the compiler it will potentially return something.

I only get an error due to the fact that you are injecting the dependency GetDataService as service but you are not creating the reference to it (aka missing the private word before the service word)
constructor(service:GetDataService){} //causes error
constructor(private service:GetDataService){} //works fine
You can see it running in this StackBlitz replication:
https://stackblitz.com/edit/angular-tdcxk7?file=src/test/test.component.ts

Related

Double Error in HTML ngtsc(-995002) Unexpected Character and Invalid ICU message

I have been looking over at my code and all over the internet for this error but cant seem to find the reason for it .
This are the two errors I got
1.Unexpected character "EOF" (Do you have an unescaped "{" in your template? Use "{{ '{' }}") to escape it.)
2.Invalid ICU message. Missing '}'
No matter how I look at it, I cant seem to find the error
This is the app.html
<section class="section is-small">
<div class="container">
<div class="columns">
<div class="column" *ngFor="let user of users">
<div class="box">
<div class="content">
<p class="has-text-centered is-size-5">{% raw %}{{user.name}}{% endraw %}</p>
<ul>
<li><strong>Role:</strong> {% raw %}{{user.role}}{% endraw %}</li>
<li><strong>Pokemon:</strong> {% raw %}{{user.pokemon}}{% endraw %}</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</section>
This is the
import { Component, OnInit } from '#angular/core';
import { UsersService } from '../services/users/users.service';
#Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit {
users;
constructor(private usersService: UsersService) { }
ngOnInit() {
this.usersService.all().subscribe(res => {
this.users = res;
});
}
}
app.component.ts
TYSM in Advance!!

How to pass value from one component to another? (Angular)

I just recently started learning Angular and I have a question. I want to implement a search method to search for a product on my site, I made search.pipe.ts, which works, but the input for input is in the header.component.ts component, and the products array is in the car-list.component.ts component.
car-list.component.html
<div *ngFor="let car of cars | paginate: { itemsPerPage: pageNumber, currentPage: currentPg} | **search:searchStr**" class="col-md-3">
<div class="product box">
<img src="{{'data:image/jpg;base64,' + car.image }}" alt="">
<h3>{{ car.name }}</h3>
<div class="price">{{ car.price | currency:'USD' }}</div>
<button class="btn btn-primary btn-sm">Add to cart</button> <!--(click)="addToCart(tempProduct)"-->
</div>
<br>
</div>
header.component.html
<form class="d-flex me-5">
<input type="text" class="form-control me-2" placeholder="Search cars...">
</form>
header.component.ts
export class HeaderComponent implements OnInit {
searchStr: string = '';
constructor() {
}
ngOnInit(): void {
}
}
search.pipe.ts
#Pipe({
name: 'search'
})
export class SearchPipe implements PipeTransform {
transform(cars: any[], value: any) {
return cars.filter(car => {
return car.name.includes(value);
})
}
}
I want the input values ​​from the header component to be passed to the car-list component so that I can find the product I need.
In this case you can use a shared service where you can pass data from your header component and load that data in your products component.
For further reference - Angular 4 pass data between 2 not related components
use #Input and #Output decorators to communicate between components

How to print key and value of object inside template?

how can I print the key and value of the object inside the template?
The template is 'kendo chart series item tooltip'
My HTML
<kendo-chart-series-item-tooltip>
<ng-template let-value="value" let-category="category" let-series="series" let-dataItem="dataItem">
<div *ngFor="let item of dataItem.subObject| keyvalue">
{{item | json}}<br/>
Key:{{item.key}} and Value:{{item.value}}
<br/><br/>
</div>
</ng-template>
</kendo-chart-series-item-tooltip>
My JSON:
[
{
"id": "1Period",
"subObject": [{"Alex":"10"},{"Mathew":"5"}],
},
{
"id": "2Period",
"subObject": [{"Alex":"2"},{"Mathew":"50"}]
}
]
This code doesn't work and it returns this error:
Uncaught Error: Template parse errors:
The pipe 'keyvalue' could not be found
probably you want to set it like this
{
"id": "1Period",
"subObject": [
{
"key":"Alex",
"value":"10"}
}
and your HTML file like this
<kendo-chart-series-item-tooltip>
<ng-template >
<div *ngFor="let item of dataItem.subObject">
<br/>
Key:{{item.key}} and Value:{{item.value}}
<br/><br/>
</div>
</ng-template>
</kendo-chart-series-item-tooltip>
You can define the following custom pipe:
import { Pipe, PipeTransform } from '#angular/core';
#Pipe({
name: 'forObject'
})
export class ForObjectPipe implements PipeTransform {
transform(value: object): string[] {
if (!value) {
return [];
}
return Object.keys(value);
}
}
And use it like that:
<kendo-chart-series-item-tooltip>
<ng-template let-value="value" let-category="category" let-series="series" let-dataItem="dataItem">
<div *ngFor="let key of dataItem.subObject | forObject">
{{dataItem.subObject[key] | json}}<br/>
Key:{{key}} and Value:{{dataItem.subObject[key]}}
<br/><br/>
</div>
</ng-template>
</kendo-chart-series-item-tooltip>
Check out my boilerplate if you have issues defining the pipe.

Angular 8 ERROR TypeError: Cannot read property 'name' of undefined

I am playing around with angular and I get this error: ERROR TypeError: Cannot read property 'name' of undefined
My code is
recipe-list.component.ts
import { Component, OnInit } from '#angular/core';
import { Recipe } from '../recipe.model'
#Component({
selector: 'app-recipe-list',
templateUrl: './recipe-list.component.html',
styleUrls: ['./recipe-list.component.css']
})
export class RecipeListComponent implements OnInit {
recipes: Recipe[] = [
new Recipe('Test', 'Test Code', 'https://cdn.pixabay.com/photo/2016/06/15/19/09/food-1459693_960_720.jpg'),
new Recipe('Test 2', 'Test Code', 'https://cdn.pixabay.com/photo/2016/06/15/19/09/food-1459693_960_720.jpg')
];
constructor() { }
ngOnInit() {
}
}
recipe-list.component.html
<div class="row">
<div class="div col-xs-12">
<button class="btn btn-success">New Recipe</button>
</div>
</div>
<hr>
<div class="row">
<div class="col-xs-12">
<app-recipe-item
*ngFor="let recipeEl of recipes"
[recipe]="recipeEl"></app-recipe-item>
</div>
</div>
<app-recipe-item></app-recipe-item>
recipe-item.compoent.html
<a href="#" class="list-group-item clearfix">
<div class="pull-left">
<h4 class="list-group-item-heading">{{ recipe.name }}</h4>
<p class="list-group-item-text">{{ recipe.description }}</p>
</div>
<span class="pull-right">
<img [src]="recipe.imagePath" alt="{{ recipe.name }}" class="img-responsive" style="max-height:50px">
</span>
</a>
recipe-item.component.ts
import {Component, Input, OnInit} from '#angular/core';
import {Recipe} from '../../recipe.model';
#Component({
selector: 'app-recipe-item',
templateUrl: './recipe-item.component.html',
styleUrls: ['./recipe-item.component.css']
})
export class RecipeItemComponent implements OnInit {
#Input() recipe: Recipe;
constructor() {
console.log('Recipe is' + this.recipe);
}
ngOnInit() {
}
}
I can't seem to find the problem with my code. Why is it adding a empty element shown in the screenshot
You can simply solve this by using the "safe navigation operator".
When you use the interpolation, it is recommended to use ? ("safe navigation") when the object may be undefined.
<a href="#" class="list-group-item clearfix">
<div class="pull-left">
<h4 class="list-group-item-heading">{{ recipe?.name }}</h4>
<p class="list-group-item-text">{{ recipe?.description }}</p>
</div>
<span class="pull-right">
<img [src]="recipe.imagePath" [alt]="recipe.name" class="img-responsive" style="max-height:50px">
</span>
</a>
This will clear your console problems, but you may need to *ngFor in a div that surrounds the component:
<div *ngFor="let recipeEl of recipes">
<app-recipe-item [recipe]="recipeEl"></app-recipe-item>
</div>
And a plus: when you are working inside a HTML tag, don't use interpolation, use property binding instead. (example [alt]="recipe.name")
I think I cracked this case: in your recipe-list component template you have <app-recipe-item></app-recipe-item> added at the end for some reason, seems like some leftover code.
The errors are likely being thrown by that component because there is no any input value provided to it. This also explains the empty element you have at the bottom of the screenshot.
Remove that and that should solve the console error you mentioned, and get rid of the empty element. Good luck!

angular2 property contains dom in template binding

I'm trying to displaying data from wordpress site in angular2 app, the wordpress post's content can contain DOM elements, but I want to render it instead of displaying it as a text.
I'm using rest API V2 plugin to get the posts from wordpress.
Home.ts
import {Component, NgFor} from 'angular2/angular2';
import {Http, HTTP_PROVIDERS} from 'angular2/http';
import {RouterLink, ROUTER_DIRECTIVES, RouteConfig} from 'angular2/router';
#Component({
selector: 'home',
viewProviders: [HTTP_PROVIDERS],
templateUrl: './app/home/home.html',
directives: [NgFor, ROUTER_DIRECTIVES]
})
export class HomeCmp {
posts: Array<any>;
constructor(http: Http) {
http.get('http://localhost/wptest/wp-json/wp/v2/posts').subscribe(res => {
this.posts = <any>res.json();
});
}
}
<h1>I'm home page</h1>
<ul>
<li *ng-for="#post of posts" class="post-item">
<a [router-link]="['/Post', {id: post.id}]">
<h3 class="post-title">
{{post.title.rendered}}
</h3>
<p class="post-excerpt">
{{post.excerpt.rendered}}
</p>
<div class="post-thumbnail"></div>
</a>
</li>
</ul>
<p class="post-excerpt" [innerHtml]="post.excerpt.rendered"></p>
Answered by Eric Martinez