Get value of Select DOM Element in ngb-tabset in Angular Bootstrap - javascript

I have the following DOM element inside a *ngFor loop (with index set to idx):
<div class="row" *ngFor="let item of myArray let idx=index">
<select [id]="'myID' + idx"></select>
</div>
In my component, I need to get the element's value and tried this:
export class HelloComponent{
constructor() {}
ngAfterViewInit(){
console.log((<HTMLSelectElement>document.querySelector('#myID0')).value);
}
}
It throws the following error:
ERROR TypeError: Cannot read property 'value' of null
When I do console.log(document.querySelector('#myID0')) I get the element printed. For some reason, I can't get the value...
UPDATE
I was missing the fact that my select is inside a ngb-tabset
You can see the reproduction of the issue here. The full HTML code is:
<ngb-tabset>
<ngb-tab>
<ng-template ngbTabTitle="">Tab</ng-template>
<div class="row" *ngFor="let item of myArray let idx=index">
<select [id]="'myID' + idx">
<option>Hello</option>
</select>
</div>
<ng-template ngbTabContent=""></ng-template>
</ngb-tab>
</ngb-tabset>

When working with Angular I would look to avoid accessing the DOM in such ways. You should look at implementing viewchildren. This should give you all the information you need about the element. Sorry answer has drastically changed since you made the stackblitz
public #ViewChildren('idx')public domElement: QueryList<any>; // be sure to import.
<select #idx> // in HTML
#ViewChildren can be used to return an array of the tagged elements. Which would be done like so. This will return you an array of the *ngFor elements.
You could then set up something simple to find the correct element.
const test = this.domElements.find(element => element.yourvalue === whatYouExpect);

Give your select elements a template reference variable, and use ViewChildren to obtain a QueryList in your component.
<div class="row" *ngFor="let item of myArray let idx=index">
<select [id]="'myID' + idx" #selectElements></select>
</div>
#ViewChildren('selectElements', { read: ElementRef })
selectElements: QueryList<ElementRef>;
See https://angular.io/api/core/ViewChildren

Related

Angular 8/9 How do I get the innerHTML of multiple elements with the same class name?

I have a div that will be created as many times as I specify, basing off of the length of a variable called totalQuestionsList. I want to select the innerHTML of all the <h5> elements inside each div.
<div *ngFor="let item of totalQuestionsList; let i = index">
<h5 class="question-num">Question #{{i+1}}</h5>
</div>
How do I do this? Any help is appreciated.
you can use a reference variable and use ViewChildren
<div *ngFor="let item of totalQuestionsList; let i = index">
<h5 #h class="question-num">Question #{{i+1}}</h5>
</div>
#ViewChildren('h') elements:QueryList<ElementRef>
You can also use a directive with selector class
#Directive({
selector:'.question-num'
})
export class QuestionDirective{
constructor(public elementRef:ElementRef){}
}
And use
#ViewChildren(QuestionDirective) elements:QueryList<QuestionDirective>
//e.g. console.log(elements.first.elementRef)
In the ts file. Inject ElemementRef into the constructor
On that class there is a nativeElement.innerHtml property
Use that to get your content

How to name dynamically a reference in a div on Angular template inside a loop

I'm developing a project using Angular 8.3.
I have a loop (using *ngFor) and I need that every div that I add has an unique reference name created dinamically).
This is my example code:
<div *ngFor="let item of list; let i = index;">
<div
cdkDropList
#done0="cdkDropList"></div>
</div>
Below I have another drag and drop zone that must receive these elements:
<div
cdkDropList
#donesList="cdkDropList"
[cdkDropListData]="DonesList"
[cdkDropListConnectedTo]="[done0, done1]"
class="movie-list"
(cdkDropListDropped)="onDrop($event)">
<div *ngFor="let itemList of DonesList" cdkDrag>{{itemList}}</div>
</div>
I need to change dynamically #done0, e.g. (#done0, #done1, #done2, #done3, etc).
How can I do it? I have tryed using #done{{i}}} but it doesn't work.
I don't know if I can use trackBy in this case and how to apply it.
Many thanks,
Reference a container:
<div *ngFor="let item of list; let i = index;" #doneContainer>
<div cdkDropList></div>
</div>
and in .ts you have different references in a NodeList:
const list = this.doneContainer.childNodes
or in a more Angular way, which is better, as it will update when necessary:
#ViewChildren('doneContainer') list: QueryList<any>;

Angular component multiple instance binding input problem

I am using an Angular Wrapper for JSON Editor like this:
<div *ngFor="let act of editedActions" class="w-100-p p-24">
{{act.test_step_id}}
<json-editor [options]="editorOptions" [(data)]="act.action_json" [(eventParams)]="act.test_step_id" (jsonChange)="changeStepActions($event)"></json-editor>
<button mat-raised-button class="w-100-p mt-24" color="primary" (click)="editRecordJson(act.test_step_id)">
<span>Update</span>
</button>
</div>
The problem is that eventParams should be different for each editor but it is not varying.
I think problem is this component code (but not sure) (This line is in the component taken from github):
#ViewChild('jsonEditorContainer', { static: true }) jsonEditorContainer: ElementRef;
The component is behaving like a singleton. Any help?
Edit: I edited this repo and added jsonchange event. Details here
You may want to use #ViewChildren with a direct reference to the component instead of a template variable string, to get all the JSON editors references:
#ViewChildren(JsonEditorComponent) jsonEditorContainers: QueryList<ElementRef>;
// ...
jsonEditorContainers.find(...);
It returns a QueryList that allows you to iterate through all ElementRef, and monitor the changes with an Observable changes.
What is eventParams? What is jsonChange? I could be wrong, but data doesn't seem to be two way bindable either, according to the source code.
It seems like you might be looking for something like this:
<div *ngFor="let act of editedActions" class="w-100-p p-24">
<json-editor [options]="editorOptions"
[data]="act.action_json"
(change)="changeStepActions($event, act.test_step_id)">
</json-editor>
</div>
You can then read the test_step_id in your changeStepActions method. If this works, I don't know how you made it compile in the first place.. are you using a CUSTOM_ELEMENTS_SCHEMA?
Its not necessary to use #ViewChildren for that you have to rewrite the entire code of component, make sure while using #ViewChild you pass correct editor reference.
As following
#ViewChild('carEditor' ) carEditor: JsonEditorComponent;
#ViewChild('mobileEditor') mobileEditor: JsonEditorComponent;
Stackblitz example for refernce :
Click here for code example
To use multiple jsoneditors in your view you cannot use the same editor options.
You should have something like:
<div *ngFor="let prd of data.products" class="w-100-p p-24" >
<json-editor [options]="makeOptions()" [data]="prd" (change)="showJson($event)"></json-editor>
</div>
makeOptions = () => {
return new JsonEditorOptions();
}

How to properly v-if and v-for nested object vue js

I cannot render nested object content with v-for, there is a prop which contain object, but the div didn't show when i do v-if="prop". Please help how to solve it. Here is the syntax that i used for render:
<div v-if="statisticBrandBrowsers && statisticBrandBrowsers.length">
<div v-for="(item, index) in statisticBrandBrowsers">
<div>View: {{item.page_view.hits}}</div>
</div>
</div>
My Props:
The problem is inside the conditional rendering not inside v-for loop because the objects don't have a property called length, so you should do something like :
<div v-if="statisticBrandBrowsers && Object.values(statisticBrandBrowsers).length">
Object.values(statisticBrandBrowsers) will give you an array which has length property

images not displaying using array with input and ngFor - Angular

I'm trying to display an array of images via their source link using an ngFor but I am receiving errors and it's not working!
The image HTML code which is within my card component:
<div class="Session-Participants">
<div *ngFor="let image of {{ participantImages }}" >
<img src='{{image}}'/>
</div>
</div>
In the JS file:
#Input() participantImages? = [];
The data is coming from my other component and the html and JS are as below:
<div *ngFor="let sessions of getSortedSessionList()">
<div *ngFor="let session of sessions">
<tl-session-card
[title]="session.name"
[path]="sessionPath(session.id, session.name)"
[participantImages]="getParticipantDetails(session)" // HERE
>
</tl-session-card>
</div>
</div>
the JS:
participantImage = [];
getParticipantDetails(session) {
this.participantImage = session.roles[0].account.thumbnailURL;
return this.participantImage;
}
I'm expecting for the 'this.participantImage' to be returned and then sent to the card component and then broken down to be displayed separately.
I'm sure I am missing something?
Thanks if you can help at all?
Actually in the stackblitz link, you have a proper array and that not reflect perfectly the code you just provide above.
You need to ensure participantImage stay an array otherwise, the ngFor will not work as expected and you will see some errors in your console.
as #prashant-pimpale says, you need to append to the list of participantImage the result.
In the ts file It would be better to use
participantImage = [];
getParticipantDetails(session) {
// ensures this.participanImage keeps its array type and will process all
// other roles
this.participantImage = session.roles.map(account => account.thumbnailURL);
return this.participantImage;
}
Hope it helps
PS: would be better to set the attribute name of participantImage to participantImages since it represent a list of images ;)

Categories

Resources