I am converting an angular 2 component to use asynchronous data sources.
I had a <div class="col s4" *ngFor="let line of lines; let i = index;"> which worked when lines was an Array of Objects, however, lines is now an Observable of an Array of Objects.
This causes error:
Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.
I tried <div class="col s4" *ngFor="let line of lines | async; let i = index;"> however, that didn't seem to make a difference.
How should I deal with this?
Here is an example binding to an observable array. It would be helpful if you posted your controller/component code too.
#Component({
selector: 'my-app',
template: `
<div>
<h2>Wikipedia Search</h2>
<input type="text" [formControl]="term"/>
<ul>
<li *ngFor="let item of items | async">{{item}}</li>
</ul>
</div>
`
})
export class App {
items: Observable<Array<string>>;
term = new FormControl();
constructor(private wikipediaService: WikipediaService) {
this.items = this.term.valueChanges
.debounceTime(400)
.distinctUntilChanged()
.switchMap(term => this.wikipediaService.search(term));
}
}
http://blog.thoughtram.io/angular/2016/01/07/taking-advantage-of-observables-in-angular2-pt2.html
Using an array from Observable Object with ngFor and Async Pipe Angular 2
The answer to the question above is this:
// in the service
getItems(){
return Observable.interval(2200).map(i=> [{name: 'obj 1'},{name: 'obj 2'}])
}
// in the controller
Items: Observable<Array<any>>
ngOnInit() {
this.items = this._itemService.getItems();
}
// in template
<div *ngFor='let item of items | async'>
{{item.name}}
</div>
Related
In Vue.js I can define named slots for my components, besides my default slot:
<article>
<header>
<slot name="header">
<h2>Default heading</h2>
</slot>
</header>
<slot/>
</article>
and then use it like this:
<template>
<FooArticle v-for="item in items">
<template #heading>
<h3>{{item}} Heading</h3>
</template>
<p>Just content</p>
</FooArticle>
</template>
<script>
export default {
name: 'App',
components: {
FooArticle
},
data() {
return {
items: ['First', 'Second']
}
}
}
</script>
Is this possible with Neos Fusion, to create a mechanism like this?
Yes this is possible, as you can use the #path decorator to overwrite a property of the wrapper element.
First you define your props and then output them in the renderer.
prototype(Foo.Components:Article) < prototype(Neos.Fusion:Component) {
heading = afx`<h2>Default heading</h2>`
content = ''
renderer = afx`
<article>
<header>
{props.heading}
</header>
{props.content}
</article>
`
}
Then you want to override these "slots" (props) from the outside with the #path decorator. The whole element the decorator is defined on will override the specified prop "heading" of the wrapping element.
prototype(Foo.Site:Home) < prototype(Neos.Fusion:Component) {
items = ${['First', 'Second']}
renderer = afx`
<Neos.Fusion:Loop items={props.items}>
<Foo.Components:Article>
<Neos.Fusion:Fragment #path="heading">
<h3>{item} heading</h3>
</Neos.Fusion:Fragment>
<p>just some content</p>
</Foo.Components:Article>
</Neos.Fusion:Loop>
`
}
FYI, we use a Neos.Fusion:Fragment object to define the path decorator, so the fragment does not render any additional markup like an enclosing <div>. In this simple case, where we only want to render a single element into the slot, we could have omitted the fragment and just set the #path="heading" directly to the <h3>.
Working example in FusionPen
Fusion AFX Docs
Neos Fusion Docs
I dont know why when i want to render a component inside of a map function, basiclly i have a List component, and when i fetch data from an API with the email, etc.. from users i want that component to render that info. But i get the following error:
Unhandled Runtime Error
Error: Objects are not valid as a React child (found: object with keys {email, phone, nick}). If you meant to render a collection of children, use an array instead.
My List component looks like this:
import React from 'react'
export default function List(email, nick, phone) {
return (
<div align="center">
<hr />
<strong>Email: </strong>
<p>{email}</p>
<strong>Nick: </strong>
<p>{nick}</p>
<strong>Phone: </strong>
<p>{phone}</p>
</div>
)
}
And my List user page looks like this:
import React from 'react'
import Nav from '../../components/Nav/Nav'
import { useEffect, useState } from 'react';
import List from '../../components/User/List';
export default function index() {
const [users, setUsers] = useState([])
const fetchUsers = async () => {
const response = await fetch("http://localhost:3001/api/internal/users");
const data = await response.json();
console.log(data["data"])
setUsers(data["data"])
}
useEffect(() => {
fetchUsers()
}, [])
return (
<div>
<Nav />
{users.map(user => (
<List
email={user.attributes.email}
phone={user.attributes.phone}
nick={user.attributes.nick}
/>
))}
</div>
)
}
UPDATE 21 ABR
For some reason when i do this :
export default function List(email, phone, nick) {
return (
<div align="center">
<hr />
<strong>Email: </strong>
<p>{email.email}</p>
<strong>Nick: </strong>
<p>{email.phone}</p>
<strong>Phone: </strong>
<p>{email.nick}</p>
</div>
)
}
It works... Someone knows what it can be?
You are passing the props in a wrong way. Either use it as a single object in props or have all the props it inside {} using destructuring method.
export default function List({email, phone, nick}) {}
OR
export default function List(props) {
return (
<div align="center">
<hr />
<strong>Email: </strong>
<p>{props.email}</p>
<strong>Nick: </strong>
<p>{props.phone}</p>
<strong>Phone: </strong>
<p>{props.nick}</p>
</div>
)
}
I'm using this code with the intent to create different tags, i.e. item.tag below:
<div v-for="item in items" :key="item.id">
<{{item.tag}}>
{{item.data}}
</{{item.tag}}>
</div>
With items defined as follows:
items: generateItems(2, i => ({
id: 'item' + i,
tag: 'hr',
data: ''
}))
But the HTML inside the div after the code runs has the < and > escaped, even though they aren't inside {{ }}, so it looks like this:
<hr> </hr>
But if I define the type explicitly:
<div v-for="item in items" :key="item.id">
<hr>
{{item.data}}
</hr>
</div>
The < and > are not escaped, and the horizontal rules display no problem.
I intend to use other tags besides hr so would like to be able to use item.tag some way.
Can anyone explain what is going on, and is there a workaround for this?
One way to do this is to use the <component :is="tag"> For example:
var demo = new Vue({
el: '#demo',
data() {
return {
tag: 'button',
othertag: 'hr'
}
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div v-html id="demo">
<component :is="tag">hello</component>
<component :is="othertag"></component>
</div>
This is mine products.component.ts and mine Json response on Node server and Angular server but i am not able to render it on my product.component.html
constructor(private http:Http) {
console.log('Hello fellow user');
this.getProducts();
this.getData();
}
getData(){
return this.http.get(this.apiUrl)
.pipe(map((res:Response)=>res.json()))
// return this.http.get(apiUrl, httpOptions).pipe(
// map(this.extractData),
// catchError(this.handleError));
}
getProducts(){
this.getData().subscribe(data=>{
console.log(data);
this.data=data;
})
}
This is mine html of product component
<p>Products work</p>
<div class="container">
<ng-container *ngFor="let product of data.products">
<h2>{{product.id}}</h2>
</ng-container>
</div>
**This is mine res.json**
First of all you should declare your data as array, as typed array if you have Product class:
data: Product[] = [];
Then I think you are wrong referring you data because into component class you assign
this.data=data;
the in your template you try to access with
data.products
Try changing *ngFor line with this:
<ng-container *ngFor="let product of data">
I need to fetch the select drop down list vales from Mongo DB mongoose.
In my angular 2 i have something which is static as:
UPDATED CODE:
I want to achieve something like this and I have tried like :
<form role="form">
<fieldset class="form-group">
<label>Select Category</label><br/><br/>
<select [(ngModel)]="selectedObject" name="first" class="form-control">
//Static data
<!--<option>Select</option>
<option>Juices</option>
<option>Chats</option>
<option>Meals</option>-->
<option *ngFor="let c of categories"
[value]="c"
[selected]="c.categoryName == selectedObject.categoryName"
>
{{c.categoryName}}
</option>
</select>
</fieldset>
</form>
In my component.ts i have something like:
export class BlankPageComponent implements OnInit {
selectedObject = null;
categories = [];
constructor(private addproductService: AddproductService,
private flashMessage: FlashMessagesService,
private router: Router) { }
ngOnInit() {
const categories = {
category_name: this.category_name
}
this.addproductService.loadData(categories).subscribe(data => {
});
\src\app\shared\services\addproduct.service.ts
export class AddproductService {
categories: any;
loadData(pList: any) {
this.categories = pList;
if (this.categories.length > 0) {
let headers = new Headers();
headers.append('Content-Type', 'application/json');
return this.http.post('http://10.22.*.*:3000/categories/get', this.categories, { headers: headers })
.map(res => res.json());
//this.selectedObject = this.categories[0];
}
}
Error as of now: TypeError: Cannot read property 'subscribe' of undefined
But i need to get the values of the drop down from backend(bind them)
In my mongoose backend i have a document with field name : category_name which has values like : Juice, Meals, Chats etc and in postman i fetch them like using API:
http://10.22..:3000/categories/get
I am able to fetch the category from nodejs using GET request,
But how to bind the select control and populate data from mongoose
.ts
categories = ['Juices', 'Chats', 'Meals'];
selectedCategory: string;
.html
<form role="form">
<fieldset class="form-group">
<label>Select Category</label><br/><br/>
<select [(ngModel)]="selectedCategory" class="form-control">
<option disabled>--Select--</option>
<option *ngFor="let category of categories" [value]="category">{{category}}</option>
</select>
</fieldset>
</form>