dynamic row creation affecting other created dropdown values angular 6 - javascript

I have 3 drop downs primary, secondary,ternary categories, each dependent on each other, Initially I have 3 drop downs below that I have one button " add more" , after clicking "add more" again drops will come below the ones earlier have, now the question is first row drop down selection is working fine , after clicking "add more" the second row drop down selection is not working , means it changes the value of already selected first row of the second category same with the ternary category. first I all load all the primary category, based on primary id i will fetch secondary categories, based on the secondary category id i will fetch ternary category. please me with this.
HTML CODE
<div class="row Space_2">
<div class="col-md-4">
<select class="Textfield_2" id="primary_category_id" formControlName="primary_category_id" (change)="getSecondCategory($event.target.value)" name="primaryServices" required>
<option value="">Primary Service</option>
<option *ngFor="let primaryCat of primaryCategory" [value]="primaryCat.id">{{primaryCat.name}}</option>
</select>
</div>
<div class="col-md-4">
<select class="Textfield_2" id="secondary_category_id" formControlName="secondary_category_id" (change)="getTernaryCategory($event.target.value)" name="secondaryServices" required>
<option value="">Secondary Service</option>
<option *ngFor="let secondCat of secondCategory" [value]="secondCat.id">{{secondCat.name}}</option>
</select>
</div>
<div class="col-md-4">
<select class="Textfield_2" id="ternary_category_id" formControlName="ternary_category_id" name="secondaryServices" required>
<option value="">Ternary Service</option>
<option *ngFor="let ternaryCat of ternaryCategory" [value]="ternaryCat.id">{{ternaryCat?.name}}</option>
</select>
</div>
</div>
<div *ngFor="let k of addmoreServices let i = index">
<div class="row Space_2">
<div class="col-md-4">
<select class="Textfield_2" id="primary_category" (change)="getSecondCategory($event.target.value)" name="{{k.primary_category}}" required>
<option value="">Primary Service</option>
<option *ngFor="let a of primaryCategory" [value]="a.id">{{a?.name}}</option>
</select>
</div>
<div class="col-md-4">
<select class="Textfield_2" id="secondary_category" (change)="getTernaryCategory($event.target.value)" name="{{k.secondary_category}}" required>
<option value="">Secondary Service</option>
<option *ngFor="let b of secondCategory" [value]="b.id">{{b?.name}}</option>
</select>
</div>
<div class="col-md-4">
<select class="Textfield_2" id="secondary_category" (change)="getTerId($event.target.value)" name="{{k.ternary_category}}" required>
<option value="">Ternary Service</option>
<option *ngFor="let c of ternaryCategory" [value]="c.id">{{c?.name}}</option>
</select>
</div>
</div>
</div>
TypeScript Code:
getPrimaryCategory() {
this.http.get('http://localhost:3000/api/getPrimaryCategory' ,{
})
.subscribe(
res => {
this.primaryCategory = res['data'];
console.log(this.primaryCategory);
},
err => {
}
);
}
getSecondCategory(id,i) {
this.primcatId = id;
this.http.get('http://localhost:3000/api/getsecondarycatdataforternary/'+id ,{
})
.subscribe(
res => {
this.secondCategory = res['data'];
console.log(this.secondCategory);
},
err => {
}
);
}
getTernaryCategory(id) {
console.log("The ternary ID is",id);
this.secondId = id;
this.http.get('http://localhost:3000/api/getternaryCatforServices/'+id ,{
})
.subscribe(
res => {
this.ternaryCategory = res['data'];
console.log(this.ternaryCategory);
},
err => {
}
);
}
getTerId(id){
this.terid = id;
console.log("THE TERNARY ID IS",this.terid);
}
addMoreServices() {
this.addmoreServices.push({ primary_category:this.primcatId , secondary_category:this.secondId ,ternary_category: this.terid });
console.log("the add more services",this.addmoreServices);
}

You need to add trackBy to your *ngFor directives. You can track by id and thanks you this Angular won't treat values after refreshing as new values.

Related

Drop down when select the option from ajax another input field appear

Hi i needed some help where if i select a drop down and select from ajax option and a hidden input field appear how can i do it ?
<div class="form-row">
<div class="col">
<label for="select-price-mode" class="col-form-label">Price Mode</label>
<select class="select-price-mode custom-select-sm col-10" id="select-price-mode" required>
<option selected disabled value="">Select ....</option>
</select>
</div>
<div class="col" hidden>
<label for="select-payment-frequency" class="col-form-label">Payment Frequency</label>
<select class="select-payment-frequency custom-select-sm col-10" id="select-payment-frequency" required>
<option selected disabled value="">Select ....</option>
</select>
</div>
This is my ajax
// Here the calling Ajax for the drop down menu below
$.ajax({
// The url that you're going to post
/*
This is the url that you're going to put to call the
backend api,
in this case, it's
https://ecoexchange.dscloud.me:8080/api/get (production env)
*/
url:"https://ecoexchange.dscloud.me:8090/api/get",
// The HTTP method that you're planning to use
// i.e. GET, POST, PUT, DELETE
// In this case it's a get method, so we'll use GET
method:"GET",
// In this case, we are going to use headers as
headers:{
// The query you're planning to call
// i.e. <query> can be UserGet(0), RecyclableGet(0), etc.
query:"PriceModeGet()",
// Gets the apikey from the sessionStorage
apikey:sessionStorage.getItem("apikey")
},
success:function(data,textStatus,xhr) {
console.log(data);
for (let option of data) {
$('#select-price-mode').append($('<option>', {
value: option.PriceMode,
text: option.PriceMode
}));
}
},
error:function(xhr,textStatus,err) {
console.log(err);
}
});
and this is my ajax response
[
{
"PriceMode": "Price By Recyclables"
},
{
"PriceMode": "Service Charger"
}
]
Where say if i select Price By Recyclables the hidden drop down list appear how can i do it ?
You can use the onchange event to trigger a check and if the user selected the value you want, then display the selectbox. You'd have to add an id to the div with the hidden prop (divToDisplay).
$("#select-price-mode").change(function() {
if(this.value === "Price By Recyclables") {
$('#divToDisplay').removeAttr('hidden');
}
});
Just invoke a function when an option is selected in first select
const checkPriceMode = () => {
let value = $('.select-price-mode').val();
$('.payment-frequency').fadeOut();
if(value === 'Price By Recyclables') $('.payment-frequency').fadeIn();
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="form-row">
<div class="col">
<label for="select-price-mode" class="col-form-label">Price Mode</label>
<select onchange="checkPriceMode()" class="select-price-mode custom-select-sm col-10" id="select-price-mode" required>
<option selected disabled value="">Select.....</option>
<option value="Price By Recyclables">Price By Recyclables</option>
<option value="Service Charger">Service Charger</option>
</select>
</div>
<div class="col payment-frequency" hidden>
<label for="select-payment-frequency" class="col-form-label">Payment Frequency</label>
<select class="select-payment-frequency custom-select-sm col-10" id="select-payment-frequency" required>
<option selected disabled value="">Select ....</option>
</select>
</div>

How to handle two selects fields in a reactive Angular form?

I have a screen where I create elements dynamically using reactive form, basically I create cards, where each has two selection fields:
Scenario: when I add a card and select a layout, the options of that specific layout are loaded in the select of assets through a service that makes the filter in the API, however when I add another card and select some other option in the layout select the two selects of assets are left with the same option.
Template
<div class="card"
formArrayName="scriptOperationOrders"
*ngFor="let workstation of formOperation.get('scriptOperationOrders')['controls']; index as idx"
>
<div class="card-body" [formGroupName]="idx">
<div class="form-row">
<div class="form-group col-md-1">
<label>Rank</label>
<input type="text" name="rank" class="form-control" formControlName="rank"/>
</div>
<div class="form-group col-md-2">
<label>Layout</label>
<select formGroupName="layout" (ngModelChange)="searchAssetsByLayouts($event)">
<option value="">Choose Layout</option>
<option
*ngFor="let lay of (layouts$ | async)?.dataArray "
[value]="lay.id">{{ lay.description }}
</option>
</select>
</div>
<div class="form-group col-md-2">
<label>Asset</label>
<select formGroupName="asset">
<option value="">Choose Asset</option>
<option
*ngFor="let asset of (assets$ | async)?.dataArray "
[value]="asset.id">{{ asset.description }}
</option>
</select>
</div>
</div>
</div>
</div>
Controller
layouts$: Observable<IResponse<ILayoutModel>>;
assets$: Observable<IResponse<IAssetModel>>;
ngOnInit() {
...
this.buildFormOperation();
this.layouts$ = this.layoutService.listLayouts();
this.providers$ = this.providerService.listProviders();
}
buildFormOperation() {
this.formOperation = this.fb.group({
script: [],
descriptionCode: [],
description: [],
scriptOperationOrders: new FormArray([])
})
}
searchAssetsByLayouts(layoutId: number) {
this.assets$ = this.assetService.listAssetsRoots(layoutId); // The assets$ variable is overridden here
}
Asset listing Service
listAssetsRoots(layoutId?: number | string): Observable<IResponse<IAssetModel>> {
return this.apiService.crudeList({
url: `${this.url}/roots`,
queryParams: {
layoutId
},
})
.pipe(map((res) => {
return new IResponse<IAssetModel>(res, IAssetModel);
}));
}
As you could be doing when selecting an option in the select layout, the options for that layout are loaded only in the select of assets on the same card
this.assets$ = this.assetService.listAssetsRoots(layoutId); as The assets$ variable is overridden here
ts file:-
//declared what type of response is expected
interface Assets{
id:number,
description :string
}
//initially set to empty
assets$ : Observable<Assets[]> = of([]);
//accepting second argument idx as row_index
searchAssetsByLayouts(layoutId: number,row_index:number) {
this.assets$[row_index] = this.assetService.listAssetsRoots(layoutId); // The assets$ variable is no more overridden
}
//html:-
//here used formControlName for 'layout' and 'asset' control insted of formGroupName
//and passed 'idx' as second parameter to (ngModelChange)="searchAssetsByLayouts($event,idx)
<div class="card"
formArrayName="scriptOperationOrders"
*ngFor="let workstation of formOperation.get('scriptOperationOrders')['controls']; index as idx"
>
<div class="card-body" [formGroupName]="idx">
<div class="form-row">
<div class="form-group col-md-1">
<label>Rank</label>
<input type="text" name="rank" class="form-control" formControlName="rank"/>
</div>
<div class="form-group col-md-2">
<label>Layout</label>
<select formControlName="layout" (ngModelChange)="searchAssetsByLayouts($event,idx)">
<option value="">Choose Layout</option>
<option
*ngFor="let lay of (layouts$ | async)?.dataArray "
[value]="lay.id">{{ lay.description }}
</option>
</select>
</div>
<div class="form-group col-md-2">
<label>Asset</label>
<select formControlName="asset">
<option value="">Choose Asset</option>
<option
*ngFor="let asset of (assets$[idx] | async)"
[value]="asset.id">{{ asset.description }}
</option>
</select>
</div>
</div>
</div>
</div>

Remove selected option from drop down in Angular

I have a button which adds more select drop downs when clicked. So I would like to remove the already selected options in these select boxes for preventing duplication.
The following code is used for the select drop down:
<select class="select form-control"
formControlName="environment_id" (change)="onEnvChange($event.target.value)">
<option selected="selected" disabled value="">Select Environment
</option>
<ng-container *ngFor="let environment of environments">
<option *ngIf="!selectedEnvironments.includes(environment.environment_id)"
[value]="environment.environment_id">
{{environment.environment_id}}</option>
</ng-container>
</select>
and in the component I ave the following function for change
public onEnvChange(selectedEnvironment)
{
this.selectedEnvironments.push(selectedEnvironment);
}
Now when I select an option, that option itself gets removed from the dropdown. For example if I have options like option1,option2,option3 etc, when I select option1, option1 is getting removed from the dropdown. How to fix this and remove the option only for the next select dropdown ?
You can try create two objects of environments and listen selection with valueChanges from formControl. After you get the selected environmentid and filter the other object without this id
Example
ngOnInit(){
this.createForm();
this.getEnvironments();
this.environmentChanges()
}
createForm(){
this.form = this.fb.group({
'environment_id_1': [''],
'environment_id_2' : ['']
})}
getEnvironments(){
const environments = [
{ 'environment_id': 1, 'environment': 'A' },
{ 'environment_id': 2, 'environment': 'B' },
{ 'environment_id': 3, 'environment': 'C' },
{ 'environment_id': 4, 'environment': 'D' }];
this.environments1 = environments;
this.environments2 = environments;}
environmentChanges(){
this.form.controls['environment_id_1'].valueChanges
.subscribe((environment_id)=>{
this.environments2 = this.environments1.filter((env)=> env.environment_id != environment_id)
})}
<form [formGroup]="form">
<div class="row">
<select class="select form-control" formControlName="environment_id_1">
<option value="">Select Environment 1 </option>
<option *ngFor="let environment of environments1" [value]="environment.environment_id"> {{environment.environment}} </option>
</select>
</div>
<div class="row" style="padding-top: 10px;">
<select class="select form-control" formControlName="environment_id_2">
<option value="">Select Environment 2 </option>
<option *ngFor="let environment of environments2" [value]="environment.environment_id"> {{environment.environment}} </option>
</select>
</div>
enter image description here

Angular 5 how to bind drop-down value based on another drop-down

I have a select drop-down that i populate from an api, i want to be able to populate a second select drop-down based on the user's first choice and subsequently populate a second drop-down based on the user's second choice.
Say i have my input fields so
form.component.html
<div class="form-group col-sm-6">
<label> Category</label>
<select class="form-control" [(ngModel)]="product.productCategory" [formControl]="productForm.controls['productCategory']" require>
<option *ngFor="let item of categorys" [value]="item.slug">{{item.name}}</option>
</select>
</div>
<div class="form-group col-sm-6">
<label> Product Type</label>
<select class="form-control" [(ngModel)]="product.productType" [formControl]="productForm.controls['productType']" require>
<option *ngFor="let item of productTypes" [value]="item.slug">{{item.name}}</option>
</select>
</div>
<div class="form-group col-md-6">
<label>Sub-Category</label>
<select class="form-control" [(ngModel)]="product.subCategory" [formControl]="productForm.controls['subCategory']" require>
<option *ngFor="let item of subs" [value]="item.slug">{{item.name}}</option>
</select>
</div>
As it is i am binding the whole list to each individual select drop-down but i want the subCategory to be only those under the selected category and same then productType based on the subCategory selected.
This is how i retrieve the category as it is the parent selection
form.component.ts
fetchCategorys() {
this.categorySrv.fetchCategories().then((response: any) => {
this.categorys = response;
console.log(this.categorys);
})
.catch(error => this.error = error)
}
I am using same method to get the subCategory and productType respectively. As you can see it brings all the items in each section from db but i want to be able to bind subCategory based on the choice of category and also bind productType based on the choice of subCategory.
Note that console.log(this.categorys) displays the category with their respective subCategory and productType but i can't figure out how to make the binding correspond.
Template
<div class="form-group col-sm-6">
<label> Category</label>
<select class="form-control" (change)="categoryChange($event)" [(ngModel)]="product.productCategory" [formControl]="productForm.controls['productCategory']" require>
<option *ngFor="let item of categorys" [value]="item.slug">{{item.name}}</option>
</select>
</div>
<div class="form-group col-sm-6">
<label> Product Type</label>
<select class="form-control" (change)="productTypeChanged($event)" [(ngModel)]="product.productType" [formControl]="productForm.controls['productType']" require>
<option *ngFor="let item of productTypes" [value]="item.slug">{{item.name}}</option>
</select>
</div>
<div class="form-group col-md-6">
<label>Sub-Category</label>
<select class="form-control" [(ngModel)]="product.subCategory" [formControl]="productForm.controls['subCategory']" require>
<option *ngFor="let item of subs" [value]="item.slug">{{item.name}}</option>
</select>
</div>
Component
public allProductTypes: ProductType[];
public allSubs: Category[];
public categoryChange( $event: Category ) {
this.productTypes = this.allProductTypes.filter( _productType => _productType.belongsTo( $event));
}
public productTypeChanged( $event: ProductType ) {
this.subs = this.allSubs.filter( _sub => _sub.belongsTo( $event ) );
}
So you bind your to the dropdown change events. Then, each time a category or product type is chosen, we filter the data that the dropdowns have available to show.
You will also probably have to reset the downstream choices, aka. when changing category, then reset product type and sub cat, because the new top level category might not allow for the old type and subcat values to exist.

Show/hide divs based on values selected in multiple select2 dropdowns

I am building a search result filtering feature. I have a number of select2 dropdown boxes where the user can select multiple values from to either hide or show divs with matching class values. I have a number of divs with classes containing values matching values in the select2 dropdown boxes. How do I go about coding this functionality?
I can only get this to work for one selection, I'd like to be able to select multiple options from the dropdowns.
$('select.filterCandidates').bind('change', function() {
$('select.filterCandidates').attr('disabled', 'disabled');
$('#candidates').find('.row').hide();
var critriaAttribute = '';
$('select.filterCandidates').each(function() {
if ($(this).val() != '0') {
critriaAttribute += '[data-' + $(this).data('attribute') + '*="' + $(this).val() + '"]';
}
});
$('#candidates').find('.row' + critriaAttribute).show();
$('#filterCount').html('Showing ' + $('div#candidates div.row:visible').length + ' Matches');
$('select.filterCandidates').removeAttr('disabled');
});
$('#reset-filters').on("click", function() {
$('#candidates').find('.row').show();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="row">
<div class="col-md-12">
<br>
<h4>Search Form</h4>
<br>
</div>
<div class="col-md-4">
<div class="form-group">
<select id="type" class="form-control filterCandidates" data-attribute="type">
<option value="0">Candidate Type</option>
<option value="CA">CA</option>
<option value="CFA">CFA</option>
<option value="CFO">CFO</option>
<option value="CIMA">CIMA</option>
</select>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<select id="role" class="form-control filterCandidates" data-attribute="role">
<option value="0">Preferred Role</option>
<option value="Analyst">Analyst</option>
<option value="Associate">Associate</option>
<option value="CFO">CFO</option>
<option value="FD">FD</option>
<option value="FM">FM</option>
</select>
</div>
</div>
<div class="col-md-4">
<div class="form-group">
<select id="roleType" class="form-control filterCandidates" data-attribute="roleType">
<option value="0">Preferred Role Type</option>
<option value="Permanent">Permanent</option>
<option value="Contract/Interim">Contract/Interim</option>
<option value="Internship">Internship</option>
</select>
</div>
</div>
</div>
just to give you a rough idea as you have not provided any code.
<script>
var SelectedValues = $('#ddlSelect option:selected');
var NotSelectedValues $('#ddlSelect option:not(:selected)');
$(SelectedValues ).each(function () {
$("."+$(this).val()+"").show(); //show all those divs containing
//this class
});
$(NotSelectedValues ).each(function () {
$("."+$(this).val()+"").hide();//hide all those divs containing
//this class
});
</script>
This is a rough idea , The above script will show all of the divs containing the classes you have selected in your select2 with id "ddlSelect" and hide those which you have not selected.
you can put this into a function and call it on onchange event of ddlSelect or whatever and however you want it to.

Categories

Resources