Dropdown default value is displayed using Angular 2/4 - javascript

<div *ngFor="let lib of library">
<input type="text" [(ngModel)]="lib.item"></div>
<div>
<md-select [(ngModel)]="lib.title">
<md-option *ngFor="let book of books" [value]="book._id">{{book.bookname}}
<md-option>
</md-select>
</div>
</div>
In my controller I have
books=[
{_id: 1, bookname:'first book'},
{_id: 2, bookname:'second book'},
{_id: 3, bookname:'third book'}
]
Interface is
export interface Ixyz{
_id: string;
item: string;
title: ICat;
}
so when I push something like
var add:Ixyz={
_id: '',
item:'',
title: 2
}
I want to be able to have default value in the dropdown. I know how to find value using ngModel. But ngModel is being used for something different.
When I push new value using title=2 it doesnt show on dropdown because title: ICat is referencing another interface.

When you add a new item into the array, just do:
var add:Ixyz={
_id: '',
item:'',
title: this.books[1]
}
This will provide a default value that should match populate the dropdown.

Related

Select Option for children it is behaving weird when parent is selected Angular

I am having an error during selecting the parent and its children on the select option.
The idea behind it is that I have for parent another select option and for the child another one.
I do have parent objects and as children nested objects which in my case are subCategory.
The problem it is that when the parent changes, the child it is empty and need to select on empty object that the list gets updated.
It is possible somehow that when parent is selected automatically show the children of the selected parent ?
Here is the code on stackblitz.
https://stackblitz.com/edit/angular-ivy-ujehrd?file=src/app/app.component.html
I have something like this.
<div class="col-md-12 pb-2">
<label>{{ "pagesInfo.categories" | translate }} </label>
<select
class="col-md-12 form-control-sm"
[ngModel]="page?.categories"
(ngModelChange)="showChildren($event)"
required
>
<option
*ngFor="let level of categoryService.categories"
[ngValue]="level"
[selected]="level"
(change)="showChildren(level)"
>
{{ level.description | translate }}
</option>
</select>
</div>
<div class="col-md-12 pb-2">
<label>{{ "categories.subCategories.name" | translate }} </label>
<select
class="col-md-12 form-control-sm"
[(ngModel)]="selectedChildren"
>
<ng-container>
<option
*ngFor="let subCat of selectedChildren"
[ngValue]="subCat"
>
{{ subCat.description | translate }}
</option>
</ng-container>
</select>
</div>
This is my TS to show the children.
selectedChildren = [];
showChildren(event) {
this.selectedChildren = [];
this.selectedChildren.push(event.subCategories);
}
And my categories looks like this.
export class Page {
_id: string;
name = "";
slogan = "";
description = "";
categories: Categories[];
}
export interface Categories {
description: string;
subCategory?: [{
name?: string,
tags?: [{
name: string
}]
}]
}
My service when I load the data.
public categories = [];
public getCategories() {
this.categories = [
{ id: Categories.Businesses, description: "categories.Businesses.name",
subCategories: [
{ id: BusinnesSubCategory.Advertising_Marketing, description: "categories.Businesses.Advertising_Marketing"},
{ id: BusinnesSubCategory.Agriculture, description: "categories.Businesses.Agriculture"}
] },
{ id: Categories.Community_Organization, description: "categories.Community_Organization.name",
subCategories: [
{ id: CommunityOrganizationSubCategory.Armed_Forces, description: "categories.Community_Organization.Armed_Forces"},
{ id: CommunityOrganizationSubCategory.Charity_Organization, description: "categories.Community_Organization.Charity_Organization"}
]},
{ id: Categories.Interest, description: "categories.Interest.name",
subCategories: [
{ id: InterestSubCategory.Literary_Arts, description: "categories.Interest.Literary_Arts"},
{ id: InterestSubCategory.Performance_Art, description: "categories.Interest.Performance_Art"},
As already pointed out by Faizal, you're using [(ngModel)]="selectedChildren" for the child select.
ngModel directive is used for the value of the <select> - you don't need to provide the list as a "model" for the selection.
The best solution is to use a different property as the model:
public selectedChild = null
`[(ngModel)]="selectedChild"`
Also there's a problem where you're pushing the whole subcategories into the selection so it is then an array of arrays of subcategories. Just assign the subcatecories as the children array.
this.selectedChildren = event.subCategories
See stackblitz: https://stackblitz.com/edit/angular-ivy-ysodem?file=src%2Fapp%2Fapp.component.html,src%2Fapp%2Fapp.component.ts,src%2Fapp%2Fcategory.service.ts

Angular - Handle all 'x' of undefined dynamically in component

I have a wrapper component which ngFor a child component. The child component receives in #input an object to format and display.
The problem is that sometimes the object is complete and displayed correctly and sometimes the object is almost empty and I have 'x' of undefined in all formatting methods, which is normal. How and in what good way can we handle all cases of 'x' of undefined globally. Based on the TypeScript interface maybe ...?
The wrapper component:
<div>
<contact-card *ngFor="let contact of contacts"
[contact]="contact">
</contact-card>
</div>
The controller of the child component :
#Input() contact: Contact;
get fullName(): string {
return `${this.contact.collaborator.fullName} ${this.contact.collaborator.lastName}`;
}
get country(): string {
return this.contact.address.country;
}
hasAccess(): boolean {
return this.contact.access.edit
}
The template of the child component :
<div>
<p>{{ contact.id }}</p>
<p>{{ fullName }}</p>
<p>{{ country }}</p>
<div *ngIf="hasAccess">
<!-- -->
</div>
</div>
This is a minimalist example. The contact object may be in the correct case :
{
id: 1,
collaborator: {
firstName: 'Jean',
lastName: 'Pierre'
},
address: {
country: 'France'
},
access: {
delete: false,
edit: true
}
}
Or :
{
id: 1
}
I also have a pipe defaultValue which displays a default value if the value is null or undefined if it can help :
<p>{{ fullName | defaultValue }}</p>
mais
Your default value pipe can help in the template, but I guess the error is triggered in the class.
You could try to give your child component's input a default value like #Input() contact: Contact = new Contact();
This way, the input will never be undefined and its value will change when it is ready.

Select v-model Object select

How we select item props together in v-model
I mean i select something only take one value.
I want to select value it should be binding name and dept together
Because i will push the these values on table.
<select v-model="name">
<option v-for="member in members" :key="member.id" :label="member.name" :value="member.name">
</option>
</select>
data(){
return {
members: [{id: 1, name: 'alpkaan', dept: 'quality'}]
}
}
I found one way it's running
:value="{'id':member.id, 'name':member.name}"
But;
Select button not work correctly. Because of v-model="name"
How solved this situation idk. :(
In your select you must have a variable that will contain the selected value,
an event that will listen to each value change and with a method related to this event, you will be able to browse your object array to find the object with the selected value.
NOTE : I delete the id with delete this.memberSelectedData.id but you can leave it if you need it, here is a screenshot.
And there is the code:
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png">
<select v-model="memberSelected" #change="slectMember()">
<option v-for="member in members" :key="member.id" :label="member.name" :value="member.name"></option>
</select>
<p>Member name : {{memberSelected}}</p>
<p>Member data : {{memberSelectedData}}</p>
</div>
</template>
<script>
export default {
name: "app",
data() {
return {
members: [{ id: 1, name: "alpkaan", dept: "quality" }, { id: 2, name: "alpkaan2", dept: "quality2" }],
memberSelected: "",
memberSelectedData: {}
};
},
methods: {
slectMember() {
this.members.map( member => {
if(member.name === this.memberSelected){
this.memberSelectedData = member
delete this.memberSelectedData.id
}
})
}
}
};
</script>

Angular 4 - make component more reusable

I want to make my component more reusable. In the component I'm binding two values with ngModel: elem.key and elem.value. The problem is that wherever I want to use this component, the element has to have key and value properties, for example some data from Api might have name, and nickname etc. For now I can use my component repeatedly, but only if the values of object are key and value. My code:
html:
<button (click)="addNew()">Add</button>
<div *ngFor="let elem of elements">
<text-input [(ngModel)]="elem.key" type="text"></text-input>
<text-input [(ngModel)]="elem.value" type="text"></text-input>
</div>
ts:
#Input() elements: any[];
addNew() {
this.elements.push({
key: '',
value: ''
});
}
If I use my component in another:
<input-key-value [elements]="values">
It works fine if I only need to add to values array {key: '', value: ''} But sometimes I want to add for example {name: '', nickname: ''}, cause data in this format must be sent to the server.
I tried add another Input name inputs, {key: 'name', value: 'name'} And in html:
<text-input [(ngModel)]="elem[inputs.key]" type="text"></text-input>
<text-input [(ngModel)]="elem.[inputs.value]" type="text"></text-input>
But this is again pushing wrong data to my main array.
This worked for me.
input-key-value template:
<div *ngFor="let elem of elements">
<div *ngFor="let prop of keys(elem)" >
<text-input type="text" [(ngModel)]="elem[prop]"></text-input>
</div>
</div>
input-key-value ts:
keys(element) {
return Object.keys(element);
}
Depending on how many properties your object has, it renders as much text boxes. Hope this will help.
In your add new function you might need to do like below
#Input() elements: any[];
#Input() elementKey: string = 'key';
#Input() elementValue: string = 'value';
addNewe() {
const element = {};
element[this.elementKey] = '';
element[this.elementValue] = '';
this.elements.push(element);
}
and in your view, you should do like below
<button (click)="addNew()">Add</button>
<div *ngFor="let elem of elements">
<text-input [(ngModel)]="elem[elementKey]"
type="text"></text-input>
<text-input [(ngModel)]="elem[elementValue]"
type="text"></text-input>
</div>
you might need to pass element key and element values when when you are using this component
when you are using your component. If you have to pass key and value like below, based on example that you have provided in comment {name: '', nickname: ''}
<input-key-value [elements]="values" [elementKey]='name' [elementValue]='nickname'>
If you are passing elements like {key: '', value: ''} then there is no requirment to pass element key and element value inputs. you can directly use it
<input-key-value [elements]="values">

Vue warn - Cannot use 'in' operator to search for '[object Array]'

Well,
I'm trying to do a project of an a Shopping cart with vue.js, and the browser Console is showing this error:
vue.common.js:576 [Vue warn]: Error in created hook: "TypeError: Cannot use 'in' operator to search for '[object Array]' in products"
// App.vue
<template>
<div class="container">
<div class="products">
<div class="clearfix">
<product v-for="product in products" :key="product"></product>
</div>
</div>
<div class="shopping-cart">
<shopping-cart></shopping-cart>
</div>
</div>
</template>
<script>
import ShoppingCart from './components/ShoppingCart.vue'
import Product from './components/Product.vue'
export default {
created () {
// dados mockados
var dummy = [
{id: 1, title: 'Name of Product 1', price: 40, image: 'product.png'},
{id: 2, title: 'Name of Product 2', price: 90, image: 'product.png'},
{id: 3, title: 'Name of Product 3', price: 10, image: 'product.png'},
{id: 4, title: 'Name of Product 4', price: 20, image: 'product.png'}
];
this.$set('products', dummy)
},
data () {
return {
products: []
}
},
components: { Product, ShoppingCart }
}
</script>
What can I do?
I tried a lot of things and still without success =(
First of all you component name in template is "product" and also the key in for loop is also "product". Either you change Component name to suitable name like.
And you must have forgot to give a name(assign a name of component for tepmplate) to component which you imported. You cannot use imported component just like that without giving it reference name to use it in template.
components: { Product:productName, ShoppingCart: shoppingCart }
This way you use <product-name> </product-name> in template and so after that in for loop, the product in prodcuts will work.
Also products array should not work with this way. It should be in computed hook.
computed ={}
Or I should suggest you should directly asssign it in data()
for better working , in the $set method in VUE
the first arg for pass 'this' keyword
some thing like this
this.$set(this,'your_object', value)
and notice second arg must be String
you must use
this.products = dummy
instead of
this.$set('products', dummy)
and if you create your array in mounted () better than created () in your single app
I think the problem is with $set method, you need to specify the object as 1st parameter, see full doc here
so you need to do something like this:this.$set(this.products, dummy)
also this will not give you 4 products in the v-for loop. I would suggest to assign the products directly in data()

Categories

Resources