Angular NgFor Path Issue - html

In my Angular Application I have a simple ngFor loop showing logo images like this:
<div *ngFor="let item of list" class="logo-wrapper">
<div class="customer-logo">
<span
class="my-icon"
aria-label="My icon"
[inlineSVG]="'./assets/image/projects/logo/' + item.logo">
</span>
</div>
</div>
This is working fine!
But: If I try to slice the Array to limit the output as follow:
<div *ngFor="let item of list | slice: 0:10; let i = index" class="logo-wrapper">
<div class="customer-logo">
<span
class="my-icon"
aria-label="My icon"
[inlineSVG]="'./assets/image/projects/logo/' + item.logo">
</span>
</div>
</div>
I get this Error : "Object is of type 'unknown'".
Error output:
I really don't know what I'm doing wrong here. I hope someone can point me in the right direction.
Edit: The problem appears as soon as I add a index to the loop.
I tried to add the index to the object like: item.i.logo but its also unknown.
PS: Here is my .ts-file
#Component({
selector: 'app-logo-section',
templateUrl: './logo-section.component.html',
styleUrls: ['./logo-section.component.scss']
})
export class LogoSectionComponent implements OnInit {
list : any
constructor()
{
this.list = getProjects()
console.log(this.list)
}
ngOnInit(): void
{
}
private services = [{
slug : "s-l-u-g",
name : "name",
work : "work",
company : "company",
website : "https://www.google.com",
preview : "text",
logo : "logo.svg"
}]
getProjects()
{
return services
}
}

You would have to change the type of list to any[] instead of any. Update the declaration as follows in your typescript file.
list : any[];

It seems like the SlicePipe deprecates with the ng-inline-svg package because it uses HttpClientModule and works asynchronously.
if you use Array.slice method instead of the SlicePipe in the *ngFor it works fine.
Please find the Stackblitz example.
<div *ngFor="let item of list.slice(0, 10); let i = index" class="logo-wrapper">
<div class="customer-logo">
<span class="my-icon" aria-label="My icon" [inlineSVG]="item.logo"> </span>
</div>
</div>

Related

Not being able to test a HTML view including an async variable in Angular

I am writing a simple test for my game component. Just checking if all child components are getting loaded in right. They all seem to work except WordFormComponent. I am guessing this is because I only render it when a async variable has been set to True. This happens only when all variables have been set.
My game.component.html looks like this:
<div class="u-w-full lg:u-w-[70%] u-mx-auto">
<a routerLink="/gameList" class="lg:u-bg-white hover:u-bg-gray-100 u-text-[13px] u-font-medium u-py-1 u-px-3 u-border u-border-gray-300 u-rounded u-flex u-items-center" style="max-width: fit-content">
<mat-icon aria-label="Submit word" class="u-h-[50%] u-text-base">keyboard_backspace</mat-icon>
Games overview
</a>
<div class="lg:u-grid u-grid-cols-3 u-gap-y-[2rem]">
<div class="u-col-span-full u-p-6 u-w-full u-bg-white u-rounded u-mt-1 u-border u-border-gray-200">
<app-final-word-form (onGuessFinalWord)="submitFinalWord($event)"></app-final-word-form>
</div>
<div clas="u-col-span-1">
<app-dashboard (onNextRound)="nextRound($event)"></app-dashboard>
</div>
<div class="u-col-span-2 u-row-span-2 lg:u-ml-[2rem]">
<div *ngIf="dataLoaded | async; then thenBlock else elseBlock"></div>
<ng-template #thenBlock>
<!-- Does not show up in test -->
<app-word-form [game]="game" [word]="word" [gameWord]="gameWord" (onGuessWord)="submitWord($event)"></app-word-form>
</ng-template>
</div>
</div>
</div>
And my test looks like this:
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ GameComponent, FinalWordFormComponent, DashboardComponent, WordFormComponent ],
imports: [ ToastrModule.forRoot() ]
})
.compileComponents();
gameFixture = TestBed.createComponent(GameComponent);
gameComponent = gameFixture.componentInstance;
gameService = TestBed.inject(GameService);
spyOn(gameService, 'createGame').and.returnValue(of({ 'Game': game, 'Gameword': gameWord, 'Word': word, 'Finalword': finalWord }));
gameFixture.detectChanges();
});
fit('should display titles of all child components', waitForAsync(() => {
gameFixture.detectChanges();
expect(gameFixture.nativeElement.querySelector('a').textContent).toContain('Games overview'); // Works
expect(gameFixture.nativeElement.querySelector('p').textContent).toContain('How to win: guess the finalword correctly.'); // Works
expect(gameFixture.nativeElement.querySelector('#wordheader').textContent).toContain('Game word.'); // Failed: Cannot read properties of null (reading 'textContent')
}));
Whenever I log this.dataLoaded when running my test it does return true. So that should not be the problem. It seems like the view does not pick up on it. Anyone knows how to make this work?

when using a GET method data is coming in console not in HTML

I have written my get method inside ngOnInIt(). When I am printing data in console it is visible, but when printing in HTML using interpolation, it is returning [ object object]
{{filteredCourses}} ==> [object object]
and when i am using {{course.category|json}} so here i am getting all values of array ["course" : "database" , "category" : "database" , "length" : "2hr" ] thats how the value is coming
html :-
<div class="courses" fxLayout="row wrap" fxLayoutAlign="center" [#animateStagger]="{value:'50'}">
<div class="course" *ngFor="let course of filteredCourses" fxFlex="100" fxFlex.gt-xs="50"
fxFlex.gt-sm="33" [ngClass]="course.category" [#animate]="{value:'*',params:{y:'100%'}}">
<div class="course-content" fxLayout="column" fxFlex="1 1 auto">
<div class="header" fxLayout="row" fxLayoutAlign="center center"
[ngClass]="course.category + '-bg'">
<div class="category" fxFlex>
{{course.category|json}}
</div>
</div>
</div>
Code:
filteredCourses: any[];
this.product_name = getProduct()['name'];
console.log(this.product_name);
this.token = getToken();
this.httpHeaders = new HttpHeaders({ "Authorization": "Bearer " + this.token });
this._httpClient.get('http://127.0.0.1:8000/api/products/info/'+this.product_name+'/',{headers: this.httpHeaders})
.subscribe(
data => {
this.product = data;
this.courses = data['cources'];
this.filteredCourses = this.courses;
console.log(this.filteredCourses);
},
error => {
console.log(error);
}
);
try using JSON.stringify(yourObject) or maybe in certain cases you can use Object.keys().
You need to use loop if its an array of object or you might want to print the properties of object individually.
But if you want to see the object filteredCourses in template, use json pipe.
{{filteredCourses | json}}
In case you need help to print values using *ngFor or properties, do let us know.
I suppose filteredCourses collection contains an array of objects. So you need to iterate through filteredCourses using ngFor directive to render data in the HTML template.
Like:
<ul>
<li ngFor="let item of filteredCourses">{{item.courseName}}</li>
</ul>

how to display data with *ngFor

i trying to display data with *ngFor, but for some reason this doesn't display any data, and any error.
I already tried alot of samples that i found in internet, none of those worked so i decide to ask here.
here is what i have:
ts file:
public querySuccess: any[];
this.userService.getMentions().subscribe(
(returnAPI) => {
this.querySuccess = returnAPI.data;
});
my html:
<div *ngIf="returnAPI">
<div *ngFor="let key of querySuccess">
<div>{{querySuccess.firstName}}</div>
</div>
</div>
<div *ngIf="!returnAPI">
<div>0 results found!</div>
</div>
the getMentions().subscribe() return this Json:
{
total: 3,
data:[
{userId: 0, firstName: "test", lastName: "xzy"},
{userId: 0, firstName: "john", lastName: "yeet"},
{userId: 0, firstName: "jamal", lastName: "abc"}]
}
You don't need that if condition to loop that ngFor.If its to show that no data error message use querySuccess because returnAPI does not seems to defined anywhere.
<div *ngIf="querySuccess">
<div *ngFor="let key of querySuccess">
<div>{{key.firstName}}</div>//key is single istance queryselector is full array.
</div>
</div>
<div *ngIf="!querySuccess">
<div>0 results found!</div>
</div>
you can try like this
<div *ngIf="returnAPI">
<div *ngFor="let key of querySuccess">
<div>{{key.firstName}}</div> <!-- key instead of querySuccess -->
</div>
</div>
Hi i would firstly recommend you put your code in a function like
ngOnInit() {
this.getAllQueries();
}
getAllQueries() {
this.userService.getMentions().subscribe(
(returnAPI) => {
this.querySuccess = returnAPI.data;
return this.querySuccess;
});
}
make sure you call this in the ngOninit function or your constructor

Using ng-repeat or ngFor to display each object in a JSON object as individual list items

I recieve an object that looks like this:
I'm trying to use ng-repeat to display the "Message", "Priority" and "DateTime" properties of each object as li items in a ul.
I've tried a couple of approaches including ng-repeat and ngFor, where all have been wrapped in divs like the first option:
This seems like the proper way to do it, but returns exactly nothing:
<div style="background: red;">
<ul>
<li ng-repeat="Notification in allNotifications">{{Notification}}</li>
</ul>
</div>
This option returns the specific object as expected:
<li style="border-radius: 3px"
[ngStyle]="{'color' : alertText}" >
Notification: {{ allNotifications.Notifications['0'].Message['0'] }}
</li>
Doesnt compile:
<li style="border-radius: 3px"
[ngStyle]="{'color' : alertText}"
[ngFor]="let subItem of allNotifications.Notifications['0'].Message['0']">
Notification: {{ subItem }}
</li>
My TS looks like this:
export class EventLogComponent implements OnInit {
constructor(private _dashdata: DashdataService) { }
NotificationName: string;
alertText: string;
allNotifications: JSON;
ngOnInit() {
this.NotificationName = 'NoNameAvailable';
this.alertText = 'Black'; //TODO: set color according to threatlevel
setInterval(() => {
this._dashdata.getAllNotifications()
.subscribe(res => {
this.allNotifications = res['notificationdata'];
console.log(this.allNotifications);
});
}, 5000); // Data Update interval in MS
}
}
ng-repeat is directive of framework AngularJS.
You are using Angular so in your case you should use ngFor:
<div style="background: red;"> <ul> <li *ngFor="let notification of allNotifications">{{notification}}</li> </ul> </div>
Using angular you should forget ng-repeat that is apart of AngularJS (version <= 1.6)
I think you have a double problem, the first one, as said, is ng-repeat, the second one is that you are not well targeting your data.
Try this
template
<div style="background: red;">
<ul>
<li *ngFor="let not of allNotifications.Notification">{{not}}</li>
</ul>
</div>

Order Json object

I'm creating a simple movie listing app with Angular 4. I'm making an HTTP GET request to fetch all the movies stored in a json file. They have some fields like "Id", "Title", "Genre", "Duration", etc. When i'm listing all the movies, how can i order them by ID descending, so that the last one appear first?
Here's the code that i am using to get this json data:
On my data service file:
getMovies(){
return this.http.get('assets/data/movies.json')
.map(res => res.json());
}
On my component.ts file:
export class MainComponent implements OnInit {
movies: Movies[];
username:string;
userimg:string;
constructor(private userService:UserService, private dataService:DataService) { }
ngOnInit() {
this.dataService.getMovies().subscribe((movies) =>{
this.movies = movies;
});
}
}
interface Movies {
id:number,
title:string,
year:number,
rating:number,
cover:string,
genre:string,
duration:string,
description:string,
favourite:number
}
On my component.html file:
<div *ngFor="let movie of movies" class="row row-movies">
<a [routerLink]="['/movies', {'id': movie.id}]">
<div class="col-md-9">
<h3> {{movie.title}}</h3>
<h4> {{movie.year}}</h4>
<h4> {{movie.rating}}</h4>
<p>{{movie.description}}</p>
<h5> {{movie.genre}}</h5>
<h5> {{movie.duration}}</h5>
</div>
<div class="col-md-3">
<img src="../assets/img/capas/movies/{{movie.capa}}" class="img-responsive capa-filme" width="350px" />
</div>
</a>
</div>
Can you help me please? I'm still very noob with Angular..
This question has nothing to do with angular. You need to do, after loading the movies, something like this:
this.movies.sort((a,b) => (b.id - a.id));
As a note: this works using any Array in vanilla javascript.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
If you don't need the sort to change, you can do it as you retrieve the data.
this.dataService.getMovies().subscribe((movies) =>{
movies.sort((a, b) => {
return a.id < b.id ? 1 : -1;
});
this.movies = movies;
});
NOTE: I did not syntax check this.