How can I display selectBox items in chips? - html

I want to display data in chips using selectBox, but I got a problem while displaying these items like this:
My TS:
selectedPointsForts: any[]=[];
listPointsForts: any[]=[];
SelectPointsForts() {
this.PointsFortsService.findAll().then((res) => {
this.listPointsForts= res.map(function(obj: any) {
return {
value: {
id: obj.id,
name: obj.libelle
},
label: obj.libelle
};
});
});
}
My HTML:
<p-multiSelect [options]="listPointsForts" [(ngModel)]=" selectedPointsForts" [selectionLimit]=3 [panelStyle]="{minWidth:'12em'}" [maxSelectedLabels]=2></p-multiSelect>
<p>Selected Cars: </p>
<p-chips [(ngModel)]=" selectedPointsForts" > </p-chips>
Can anyone help me to fix this problem !

You can place pTemplate in <p-chips> element to format the chip items' displayed output.
<p-chips [(ngModel)]="selectedPointsForts">
<ng-template let-item pTemplate="item">
{{ item.id }} - {{ item.name }}
</ng-template>
</p-chips>
Sample Solution on StackBlitz
Output
References
Chips (Custom Content)

Related

How to have 2 different results in a bootstrap dropdown separated by a heading?

I am trying to show different results in a single autocomplete result differentiating with the heading. I have 2 roles Subject and Teacher, when searching with some letter I want to show both the results of Teacher and Subject, but want to differentiate as below
Expected Output
expected output
Teacher heading will differentiate the 2 result sets
The output I am getting
Subject
Math
...
Maddy
....
The link to the code is here
Any help is much appreciated.
Thanks in advance!!
Slightly updated logic:
Typescript:
export class AppComponent {
typeahead: FormControl = new FormControl();
countries = countries;
suggestions = {
countries: [],
teachers: [],
};
suggest() {
this.suggestions = {
countries: this.countries
.filter(c => c.role === 'Subject')
.filter(c => c.name.startsWith(this.typeahead.value))
.slice(0, 5),
teachers: this.countries
.filter(c => c.role === 'Teacher')
.filter(c => c.name.startsWith(this.typeahead.value))
.slice(0, 5),
};
}
}
HTML:
<input type="text" [formControl]="typeahead" placeholder="Type ahead !" (input)="suggest()">
<div class="suggestions">
<ng-container *ngFor="let s of suggestions.countries; let i = index">
<h3 *ngIf="i === 0">{{ s.role }}</h3>
<p>{{ s.role }} - {{ s.name }}</p>
</ng-container>
<ng-container *ngFor="let s of suggestions.teachers; let i = index">
<h3 *ngIf="i === 0">{{ s.role }}</h3>
<p>{{ s.role }} - {{ s.name }}</p>
</ng-container>
</div>
Your example doesn't work because in html only the first element is being checked (when deciding when to put h3 tag) and it was with the role Teacher. Splitting into 2 fields will result in you being able to separately iterate each of them and apply logic (in this case, check if i === 0).

V-for from a nested array

I'm starting with vue.js and I need to populate selects with v-for that are inside another v-for.
I was reading questions about this subject but could not find a way to make it works in my case.
I have a nested array (tours) with title and description and I have a v-for inside another one to populate a select with tours' title:
html:
<div class="row" id="app">
<div v-for="(item, index) in hosters" v-bind:key="item.id" class="col-md-6 mb-50">
<h4 class="mb-0">{{ item.name }} {{ item.lastname }}</h4>
<div class="tour-options-select">
<select id="select-suggestions" name="tour-options-dropdown" class="tour-options-dropdown">
<option v-for="tour in tours">{{ tour.title }}</option>
</select>
</div>
</div>
</div>
vue.js:
let app = new Vue({
el: '#app',
data: {
city: 'mycity',
hosters: null,
tours: [],
title: [],
},
created: function () {
this.searchHoster()
},
methods: {
searchHoster: function () {
axios.post('searchHoster.php', { "city": this.city }).then((response) => {
this.hosters = response.data.hosters;
console.log(this.hosters);
this.tours = this.hosters.map(res => res.tours);
console.log(this.tours);
this.title = this.tours.map(res => res.title);
console.log(this.title);
}).catch((error) => {
console.log(error);
});
},
}
})
I’m getting undefined in console.log(this.title); line so i tried to use:
this.title = response.data.hosters.map(hoster => hoster.tours).flat().map(item => item.title);
but it gives me a simple array with all the titles of all users. So, all selects are populated with the same titles for everyone. Any tip about how to make it works?
Change tours to item.tours on second v-for:
<div v-for="(item, index) in hosters" v-bind:key="item.id" class="col-md-6 mb-50">
<h4 class="mb-0">{{ item.name }} {{ item.lastname }}</h4>
<div class="tour-options-select">
<select id="select-suggestions" name="tour-options-dropdown" class="tour-options-dropdown">
<option v-for="tour in item.tours">{{ tour.title }}</option>
</select>
</div>
</div>
Do not break out the various pieces of data you are interested in rendering. Instead, render the inner portions using the index value from the outer v-for. For example, assuming your data looks like the data you depicted, then...
V-for="item in data"
Render host info using item.name, etc.
v-for="tour in item.tours"
Render title and description from tour.title, etc.
Much faster and easier. I might also suggest using an accordion type control as well - render a table of all the tours, and allow user to select the desired row by check box (which would then display further details in a details area). - that way they can see all the options easily. Make the items collapsible using #click to toggle a boolean value which controls show=boolean on a nested div.
Good luck.
<div class="tour-options-select">
<select id="select-suggestions" name="tour-options-dropdown" class="tour-options-dropdown">
<option v-for="tour in ̶t̶o̶u̶r̶ item.tours">{{ tour.title }}</option>
</select>
</div>
Change the tours to item.tours
Since you are already iterating through the first v-for the context for the 2nd v-for is "item". and item.tours would give you the proper object to iterate over.

Hide element using ngFor and ngIf

I want to hide the other 3 elements in li element after the one of the list was clicked (the clicked list remain unhide), as I try it hide all the li element.
payment.component.ts
paymentLists = [
{
name: 'IpayEasy',
},
{
name: 'Credit Card',
},
{
name: 'Internet Banking',
},
{
name: '7-Eleven',
},
];
selectedIndex: number;
select(index:number) {
this.selectedIndex = index;
}
payment.component.html
<ul *ngIf="selectedIndex == paymentList">
<li (click)="select(paymentList)"
*ngFor="let paymentList of paymentLists; let i=index">
<span>{{paymentList.name}}</span>
</li>
</ul>
Here what have I tried,
demo
Before:
IpayEasy
Credit Card
Internet Banking
7-Eleven (clicked li)
After:
7-Eleven (li element remain unhide)
You need to update your template as following
Move ngFor to ng-container element
Update ngIf condition to be true only if there is no selected index or the matching selected index
Pass index in select function
Updated html will be as follows
<ul>
<ng-container *ngFor="let paymentList of paymentLists; let i=index" >
<li (click)="select(i)" *ngIf="selectedIndex === undefined || selectedIndex == i" [ngClass]="{'tab__list--selected--mobile': selectedIndex == paymentList}">
<span>{{paymentList.name}}</span>
</li>
</ng-container>
</ul>
For reference, here is the working version
try
<ul *ngIf="selectedIndex == paymentList">
<ng-container *ngFor="let paymentList of paymentLists; let i=index">
<li (click)="select(paymentList)" *ngIf="!selectedIndex || selectedIndex=i">
<span>{{paymentList.name}}</span>
</li>
</ng-container>
</ul>
you can use this code instead of yours :
your ts:
select(index) {
this.paymentLists = [index];
}
your HTML:
<ul *ngIf="selectedIndex == paymentList">
<li (click)="select(paymentList)"
*ngFor="let paymentList of paymentLists; let i=index">
<span>{{paymentList.name}}</span>
</li>
</ul>
Just for the record, Since my previous answer wasn't very clear. Here is a thorough explanation to the solution for the aforementioned problem.
paymentLists = [
{
name: 'IpayEasy',
},
{
name: 'Credit Card',
},
{
name: 'Internet Banking',
},
{
name: '7-Eleven',
},
];
selectedIndex: number;
select(index:number) {
this.selectedIndex = this.paymentLists.findIndex(x => x.name==paymentListNameObject.name);
this.paymentListSelected = true;
}
in the above mentioned code, the select function recieves an object instead of the index number. which can be corrected as above. Also i added a variable paymentListSelected. this variable tracks if a particular payment method has been selected.
In the HTML, you could get rid of *ngIf="selectedIndex == paymentList" and use the following:
<ul>
<li *ngFor="let paymentList of paymentLists; let i=index" (click)="select(paymentList)"
[ngClass]="{'tab__list--selected--mobile': ((i == selectedIndex)&&paymentListSelected),'hide-tab__list--unselected--mobile': paymentListSelected}">
<span>{{paymentList.name}}</span>
</li>
</ul>
Here i add 2 classes tab__list--selected--mobile which is applied to the selected payment method based on the index number which was selected by the user. And to hide the other options, i added hide-tab__list--unselected--mobile to all other options.
Finally here is a working link just in case the explanation wasn't clear enough.
https://stackblitz.com/edit/angular-display-list-d19ffv
This answer i guess qualifies for not getting DELETED!!!!!

Displaying comma separated string in Angular 6

I am trying to loop through a comma separated string in Angular 6.
public getCategory(){
this.Jarwis.getCategorys().subscribe((data: Array<object>) => {
this.categorys = data;
console.log(this.categorys);
});
This is my function which have a console log as
(3) [{…}, {…}, {…}, {…}, {…}, {…}]
0: {id: 4, category_name: "Agriculture", sub_category_names: "Other Agriculture,Vineyards and Wineries,Greenhouses,Tree Farms and Orchards"}
1: {id: 5, category_name: "Automotive and Boat", sub_category_names: "Auto Repair and Service Shops,Car Dealerships,Marine/Boat Service and Dealers,Junk and Salvage Yards"}
2: {id: 13, category_name: "Beauty and Personal care", sub_category_names: "Massage,Tanning Salons,Spas,Hair Salons and Barber Shops"}
I can display category name in view page with the help of
<li *ngFor='let category of categorys'>
<div>{{ category.category_name }}</div>
</li>
But how can I display sub_category_names in different divs just like this
<div> subcategory_name1 </div>
<div> subcategory_name2 </div>
Please help
You can use a custom pipe to split the array:
#Pipe({
name: 'splitComma'
})
export class SplitCommaStringPipe implements PipeTransform {
transform(val:string):string[] {
return val.split(',');
}
}
and use it like:
<div *ngFor="let subcategory of category.sub_category_names|splitComma">
{{subcategory}}
</div>
Use following code in your html:
<li *ngFor='let category of categorys'>
<div>{{ category.category_name }}</div>
<div *ngFor="let subCategory of category.sub_category_names?.split(',')">
{{ subCategory }}
</div>
</li>
May be you can try this way by using an additional *ngFor
<li *ngFor='let category of categorys'>
<div *ngFor="let subCategory of (category.sub_category_names.split(','))">{{ subCategory }}</div>
</li>
https://stackblitz.com/edit/angular-a4s1bq
You can also split the sub-categories on return of the data. And then use *ngFor on the sub-categories. In ES6 this would look like this:
this.categories = data.map((e => {
return {
...e,
sub_category_names: e.sub_category_names.split(',')
}
}));
btw. plural of category is categories
https://stackblitz.com/edit/js-rkkyjs

Display JSON Object to front end using services in Angular2

I have been trying to display a json file having multiple arrays in it on the front-end div tag in using Services Angular2 using Typescript. Can anyone help?
Also, If anyone can help transforming this code by adding Model and Interface class would be very helpful.
Here is the code:
SERVICE
export class HttpServiceDemo{
_data: any;
private url: string = "assets/sample.json"
constructor(private http: Http){}
getMyOrder(){
//return this.http.get(this.url)
// .map((response: Response)=> response.json());
return this.http.get(this.url)
.map(res => this.http = res.json().myOrder);
}
}
component.ts
export class SimpleHTTPComponentComponent implements OnInit {
data:any;
Order_date:any;
OrderNumber: number;
P_O_Number:number;
Total: number;
Quote_Status: string;
Expiration_Date: any;
Quote_Created_On: any;
constructor(public vara: HttpServiceDemo) {
}
ngOnInit() {
//calling myorder from json
this.vara.getMyOrder().subscribe(response => {
this.data=response;
for (var myOrder in this.data)
{
console.log(myOrder, this.data[myOrder]);
this.Order_date=this.data[myOrder].Order_Date;
this.OrderNumber=this.data[myOrder].OrderNumber;
this.P_O_Number=this.data[myOrder].P_O_Number;
this.Total=this.data[myOrder].Total;
this.Quote_Status=this.data[myOrder].Quote_Status;
}
})
}
sample.json
---------------
{
"accOrder":[
{
"Order_Date": "10-sep-1981",
"OrderNumber" : "E12345",
"P_O_Number": "P12345",
"Total": "123",
"Quote_Status": "In Progress"
},
{
"Order_Date": "1-oct-1981",
"OrderNumber" : "E82398",
"P_O_Number": "P87815",
"Total": "265",
"Quote_Status": "In Progress"
},
{
"Order_Date": "21-nov-1981",
"OrderNumber" : "E52367",
"P_O_Number": "P76549",
"Total": "454",
"Quote_Status": "In Progress"
},
{
"Order_Date": "10-dec-1981",
"OrderNumber" : "E42840",
"P_O_Number": "P23632",
"total": "123",
"Quote_Status": "Completed"
}
]
}
You are saying your console.log() shows the JSON just fine ?
Then, your data is correctly fetched into your component's data attribute.
You just have to go through your attribute in your template using *ngFor directive then.
Plunkr : https://plnkr.co/edit/4IdV3OHyNFNi90KXQQHP?p=preview
template: `
<div>
<div *ngFor="let order of data.accOrder" style="border: 1px solid lightgrey; padding: 15px; margin: 5px 0;">
Order_Date : {{ order.Order_Date }} <br>
OrderNumber : {{ order.OrderNumber }} <br>
P_O_Number : {{ order.P_O_Number }} <br>
Total : {{ order.Total }} <br>
Quote_Status : {{ order.Quote_Status }} <br>
</div>
</div>
`
PS : No need for your "for" loop inside ngOnInit() , this is not how you should access the data.
You should check out the ngFor doc to learn more about it.
EDIT :
As I said in my comment below, my previous Plunker was using raw data while you use asynchronous data in your use case (it's coming from an Observable sent from your service).
To make it work then, you have to check if your component already received the data before you try to display it. For that, you need to use the *ngIf directive.
New Plunkr : https://plnkr.co/edit/W5qykrh4blplGxTyp8aC?p=preview
template: `
<div *ngIf="data; else loading">
<div *ngFor="let order of data.accOrder" style="border: 1px solid lightgrey; padding: 15px; margin: 5px 0;">
Order_Date : {{ order.Order_Date }} <br>
OrderNumber : {{ order.OrderNumber }} <br>
P_O_Number : {{ order.P_O_Number }} <br>
Total : {{ order.Total }} <br>
Quote_Status : {{ order.Quote_Status }} <br>
</div>
</div>
<ng-template #loading>Fetching the data from the webservice... Wait 3 seconds !</ng-template>
`,
You have to create a parent div to the one with your *ngFor directive. In this parent div, use the *ngIf="data" directive. Everything inside it will not be displayed until there is some data into the data attribute.
I used here an if/else syntax which appeared with Angular4. But you don't need that. That's just here to display a message while there is no data. It could be a loading spinner for example, to let the user know he has to wait.
If you don't want to use this if/else condition, you can do it without it like that :
template: `
<div *ngIf="data">
<div *ngFor="let order of data.accOrder" style="border: 1px solid lightgrey; padding: 15px; margin: 5px 0;">
Order_Date : {{ order.Order_Date }} <br>
OrderNumber : {{ order.OrderNumber }} <br>
P_O_Number : {{ order.P_O_Number }} <br>
Total : {{ order.Total }} <br>
Quote_Status : {{ order.Quote_Status }} <br>
</div>
</div>
`,
Hope this helped :)