Angular #Input property - missing first value from array - javascript

I have a problem with sending values from one component to other. I've got 2 components: report-form and comment-form. Report form have an array of comments. It also show list of comment and button for each of them. After clicking a button It should load modal form with #Input property commentIndex. Problem is that report-form component don't send only(!) first value of array to comment-form. I don't have idea why :/.
Here's some code:
Part of report-form.html:
<div class="form-group row">
<div class="col-md-12 alert alert-dark">Komentarze:</div>
<div class="col-md-12" *ngFor="let comment of comments">{{ comment.content }}
<app-comment-form [commentIndex]="comments.indexOf(comment)"></app-comment-form>
</div>
<br>
<app-comment-form></app-comment-form>
</div>
If I log it on console in comment-form I've got 1,2 in 3 elements array but where's 0?!

You can use index provided by the *ngFor directly.
<div class="form-group row">
<div class="col-md-12 alert alert-dark">Komentarze:</div>
<div class="col-md-12" *ngFor="let comment of comments; let i = index">{{ comment.content }}
<app-comment-form [commentIndex]="i"></app-comment-form>
</div>
<br>
<app-comment-form></app-comment-form>
</div>
This index will start from 0.

Related

angular 2 : multiple use of one component in parent component

I have CarsComponent that I multi time use ChartComponent in it's template as I mentioned in code snippet:
cars.component.html:
<div class="row" *ngIf="selectedItemId">
<div class="col-12 mb-2">
<report-chart [LegendData]="xAxisData1"
[SeriesData]="yAxisData1"
title="میزان خروج وسیله ی نقلیه از مراکز تولید"
barChartColor="#ad106c"
(onReportClick)="getProductReport()">
</report-chart>
</div>
<div class="col-12">
<report-chart [LegendData]="xAxisData2"
[SeriesData]="yAxisData2"
barChartColor="#3398DB"
title="میزان ورود وسیله نقلیه به مراکز فروش"
(onReportClick)="getSaleReport()">
</report-chart>
</div>
</div>
and and in my ChartComponent I use radio-button-group like this:
chart.component.html:
<nb-radio-group [(ngModel)]="selectedChart" class="d-flex justify-content-center">
<nb-radio class="d-flex justify-content-center"
*ngFor="let option of radioButtonsOptions"
[value]="option.value">
{{ option.label }}
</nb-radio>
</nb-radio-group>
my problem is when report-chart load in cars-component selected radio button only show in one instance and I want to prevent affection of two instance to each other
If I understand correctly you want to enable the ratio buttons only in the second child component and not the first.
The solution would be to pass a boolean input in the child component to show or not the ratio button.

Vue TypeError: Cannot read property '_wrapper' of undefined when attempting to update Object property

I am trying to use a button to update a property of an Object in Vue. The Object is returned by an AJAX query to a database, and the isFetching boolean is then set to false, which attaches the containing div to the DOM. When I try and update the property, I get the following error:
TypeError: Cannot read property '_wrapper' of undefined
Below is my AJAX code:
axios.post("/api/myEndpoint", { id: router.currentRoute.query.id })
.then((response) => {
this.activities = response.data.activities;
this.isFetching = false;
})
.catch((errors) => {
console.log(errors);
router.push("/");
});
Here is my HTML:
<div v-if="isFetching">
<h2>Loading data...</h2>
</div>
<div v-else>
<div class="row no-gutters">
<div class="col">
<div class="d-flex flex-row justify-content-center">
<h4>Activities</h4>
</div>
<div class="custom-card p-2">
<div class="row no-gutters pb-4" v-for="(activity, index) in activities"
:key="activity.stage_id">
<button v-if="!activity.is_removed" class="btn custom-btn" :class="{'hov':
index == 0}" :disabled="index != 0"
#click="markRemoved(activity)">Remove</button>
</div>
</div>
</div>
</div>
</div>
Finally, here is markRemoved() as called by the button's click listener:
markRemoved(a) {
a.is_removed = true;
}
When I try and log a in markRemoved() the Object is logged to the console fine, exactly as expected. Having stepped through it in the debugger, the exception is thrown at the point I try and update the is_removed property of the Object.
Does anyone know what I'm doing wrong here?
Note: the id I pass to the AJAX query is a query parameter of Vue Router. This is also set correctly and passed as expected.
Here is an example activity Object:
{date_time_due: "2020-12-09T11:43:07.740Z"
date_time_reached_stage: "2020-12-02T11:43:07.740Z"
is_complete: true
is_removed: false
selected_option: "Some text"
stage_id: 1
stage_name: "Some text"}
The exception is only thrown on the first click of the button.
Posting in case anybody else comes across this error in the future.
Vue requires exactly one root element within a single-file component's <template> tags. I had forgotten about this and in my case had two <div> elements, shown one at a time, conditionally using v-if:
<template>
<div v-if="fetchingData">
<h2>Loading data...</h2>
</div>
<div v-else>
<!-- The rest of the component -->
</div>
</template>
This caused problems with Vue's reactivity, throwing the error whenever I tried to update some part of the component. After realising my mistake, I wrapped everything in a root <div>. This solved the issue for me:
<template>
<div id="fixedComponent">
<div v-if="fetchingData">
<h2>Loading data...</h2>
</div>
<div v-else>
<!-- The rest of the component -->
</div>
</div>
</template>

Angular 6: onChage mat-slide-toggle conditional validation to select only one option from array of objects

I have a list of the mat-slide-toggle. At a time only one slider will remain enabled and other slider will remain disabled.
Now while clicking on that enabled slider it's value will be changed and simultaneously other list of slider will be get enabled for selection and once the one slider will be get selected then other will be get disabled.
So, in short from the whole array only one mat-slide-toggle should be selected and other will be disabled simultaneously.
For that I have make the code as below.
<form [formGroup]="selectionForm">
<div class="row">
<div formArrayName="selectOption">
<div *ngFor="let select of selectionForm['controls'].selectOption['controls']; let i=index">
<div [formGroupName]="i">
<div formArrayName="selectionList">
<div *ngFor="let obj of select.controls['selectList'].controls; let j = index">
<div [formGroupName]="j">
<mat-slide-toggle formControlName="isSelected"" (change)="changeSelection($event)" disabled="slidValue || obj.isSelected === false"> Is selected? </mat-slide-toggle>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</form>
In TS code:
public slidValue;
changeSelection(event) {
this.slidValue = false
}
Sample JSON Response
StackBlitz demo.
Eg: On load of the page:
Now when change the slide toggle all other options value not getting change from false to true for selection.

use ngFor loop in Angular 6 to dynamically create array of input elements and add dynamical validation based on template reference variables

I would like to create dynamically 3 input tags in Angular 6 to not copy/paste html code because that input elements have similar html and functionality.
For this purpose I created an array "reusableItems" inside component and initialize it :
let numberOfInputElements = 3;
for (let i = 0; i < numberOfInputElements; i++) {
this.reusableItems.push({
answer: 'Answer ' + (i +1),
passwordRecoveryAnswer: this.user['passwordRecoveryAnswer' + (i + 1)]
});
}
Then I put code inside my html :
<div *ngFor="let item of dropDownDataManagerService.reusableItems" >
<li class="col-xs-12 pl-lg pr0 pv-sm bd1-bottom">
<div class="col-xs-4 ph0 pt"> {{item.answerTitle}}</div>
<div class="col-xs-8">
<input type="text" name={{item.answer}} ref-{{item.answer}}="ngModel" class="col-sm-12 k-textbox ph0"
[(ngModel)]=item.passwordRecoveryAnswer
[pattern]="[a-z]"
required autocomplete="off"/>
</div>
</li>
</div>
It seems works fine but then I need to add error messages when these fields will be empty and not match to pattern. Something like :
<div *ngIf="__{{item.answer}}__.errors?.required ">
{{'Please provide an answer' | translate}}
</div>
<div *ngIf="__{{item.answer}}__.errors?.pattern">
{{'Pattern is not match'}}
</div>
I don't know what should i put inside ngIf condition.
How can I do it if my template reference variables are comes from array?
Is anyone have ideas?
Thanks
Angular creates unique template reference variable for each embedded template so that you can use the same template reference variable name inside ngFor loop:
<div *ngFor="let item of reusableItems">
<li class="col-xs-12 pl-lg pr0 pv-sm bd1-bottom">
<div class="col-xs-4 ph0 pt"> {{item.answerTitle}}</div>
<div class="col-xs-8">
<input type="text" name={{item.answer}} ref-answer="ngModel" class="col-sm-12 k-textbox ph0" [(ngModel)]="item.passwordRecoveryAnswer"
[pattern]="'[a-z]'" required autocomplete="off" />
<div *ngIf="answer.errors?.required">
{{'Please provide an answer'}}
</div>
<div *ngIf="answer.errors?.pattern">
{{'Pattern is not match'}}
</div>
</div>
</li>
</div>
In the code above I use the same name for each input in array
ref-answer="ngModel" // or you can also use #answer="ngModel

Angular 2 NgFor Pattern Error Message Not Showing

I'm trying to have inputs with a regex requirement in a ngFor loop but am not seeing the error message as expected when I put something that doesn't match the required pattern.
"Test" is never hidden and <div *ngIf="id?.hasError('pattern')"> never shows, even when I enter the wrong pattern. I can see that the input fails because I'm using Material Design and the color of the line underlining the input changes to red but I do not see any changes in regards to the error messages.
Here is my code at the moment:
(The keys pipe I have is a custom pipe because item is an object made of objects, so that breaks down the contained objects into key/value pairs.)
<div *ngFor="let item of items | keys">
<md-input-container>
<input
mdInput
placeholder={{item.placeholder}}
name={{item.name}}
pattern="\d{7}"
[(ngModel)]="item.currentValue"
#id="ngModel"
>
</md-input-container>
<div
[hidden]="id?.valid || id?.pristine"
>
<p>Test</p>
<div *ngIf="id?.hasError('pattern')">
Pattern should be xxxxxxx
</div>
</div>
</div>
Try by changing name={{item.name}} to name="id".
Try it in next way:
<div *ngFor="let item of items | keys">
<md-input-container>
<input
mdInput
placeholder={{item.placeholder}}
name={{item.name}}
pattern="\d{7}"
[(ngModel)]="item.currentValue"
#id="ngModel"
>
</md-input-container>
<div [hidden]="!displayValid(id)">
<p>Test</p>
Pattern should be xxxxxxx
</div>
</div>
And this fun in .ts file of component:
displayValid(inputRef: any): boolean {
let errors: any = inputRef.errors;
return errors && errors.pattern;
}

Categories

Resources