Hide a particular instance of a repeating component - javascript

I have a table with an ngFor iterating over a collection. For each item in the collection it will produce a row containing a single cell. The cell contains a button and custom component. The custom component has an ngIf directive which only shows the custom component if the device is deemed to be online. I'd like to be able to toggle the visibility of the custom component by clicking the button also. How do I pass the particular instance of the custom component in the table cell to the onExampleBtnClick() function? I do not wish to show/hide all instances of the custom component, only the one that shares the cell with the clicked button. Thanks
<table>
<tr *ngFor="let item of items;let indexOfelement=index;">
<td>
<button type="button" (click)="onExampleBtnClick($event)" #ExampleButton>Click Me</button>
<custom-comp *ngIf="showIfDeviceOnline"></custom-comp>
</td>
</tr>
</table>

You can create another property on your data array which will keep track of if the component need to be shown or not. You dont need to touch existing data creating a new array of object using map function like below.
export class AppComponent {
title = "CodeSandbox";
Items:string[] = ['Apple','Oranges'] ;
data: any = null;
ngOnInit(){
this.data = this.Items.map(x=> {
return {
name: x,
show:true
}
});
}
hide(item){
item.show = false;
}
}
and based on that you can apply *ngIf condition on container like below.
<div>
<div *ngFor="let item of data">
<ng-container *ngIf="item.show">
<button type="button" (click)="hide(item)"> Click Me</button>
<app-custom></app-custom>
</ng-container>
</div>
</div>
Here is the codesandbox
https://codesandbox.io/s/pedantic-forest-871qc?file=/src/app/app.component.ts:160-449
Another approach is the create a mapper object which will keep track of status of each item of array and based on the status hide the component.

Local references is what I was looking for. I can wrap the custom component in a div and apply a local reference of #CustComp and then pass CustComp to the onExampleBtnClick function. It will reference the actual instance and allow me to target it's hidden property.

Related

Angular loop over reactive form controls from HTML

I have a HTML table that is creating a TR component based on an ngFor loop.
<tbody>
<tr *ngFor="let t of intakeForm.controls['tasks'].value let i = index; trackBy:trackByIndex" [taskTR]="t" [ui]="uiOptions" [tasks]="configuredTasks" [intakeForm]="intakeForm"></tr>
</tbody>
Currently, I am looping over the value of the form for these controls but I am trying to loop over the controls instead so I can pass them to the trcomponent.
Something like:
let t of intakeForm.controls['tasks'].controls
tasks is a form array and I am trying to loop over the array of controls it has so that I can pass it to the component.
I tried this let t of (<FormArray>intakeForm.controls['tasks'].controls) but it didn't work. Not sure that it can be done within the html like that.
End goal here is that I want to pass the form control on each iteration to the tr component.
Try using the get method within form groups to inspect specific controls. It's a much cleaner way of accessing controls within form groups.
Also using the methodology below allows you to "drop" into each element within the array and access the properties directly within your template since you are already "within" the correct formGroup in the FormArray. So no need for long prefixes with indices to define which element of the FormArray you are working on.
<ng-container formArrayName="tasks">
<tr [formGroupName]="i" *ngFor="let task of intakeForm.get('tasks').controls; let i=index">
<input type="text" formControlName="taskName" />
</tr>
</ng-container>

Dynamically appending child nodes with Ionic CSS

I want to add styles from the Ionic CSS library to the HTML element created in Javascript. The purpose is because I'm pulling objects from my database and dynamically creating buttons for them. I can receive these items and add them to the page but I'm unable to use format it properly. This is a basic HTML example of what I want to replicate in JavaScript.
<ion-list id="list" (click)=add()>
<button ion-item>
<ion-icon name="ios-add" item-start></ion-icon>
Add
</button>
</ion-list>
To produce this button:
This is what I have in Javascript.
add() {
var listItem = document.getElementById("list");
var listButton = document.createElement('button');
listButton.setAttribute("class","ion-item");
listButton.setAttribute("id", id+"1");
var icon = document.createElement("ion-icon");
icon.setAttribute("name","ios-add");
let text = document.createTextNode("Add");
listButton.appendChild(text);
listButton.appendChild(icon);
listItem.appendChild(listButton);
}
This is what the above[code produces:
How can I use JavaScript to manipulate the DOM while retaining Ionic formatting?
Using: Node 8.3.0, Angular 4, Ionic 3.
I have a similar problem, what I am pushing the objects to an array every time I clicked on an object, I would push it to the array created in the front-end and display the array of objects in a separate component, that way I can style only the selected items.
The other option would be to copy the whole data objects and add props of boolean type like "added" or "in_playlist" but there may be a lot of data therefore I would suggest the first solution.

Vue.js weird rendering with class binding

So basically I have an html table with a v-for that loops over an array of objects, nothing complicated here. When the user clicks on a row, it toggles the selected property of the object "linked" to the given row.
Now, I also setup a simple class-binding with v-bind:class="{'active': n.selected}" where n is my object, but it doesnt update. Now what is more weird is that I use the webpack template from the vue-cli, and when I :
Select a bunch of rows (no active class binded)
update code
hit F5 which triggers the webpack hot-reload
The selected rows suddenly get the active class, as the CSS says so, until the webpack hot-reload has regenerated the page.
Here is my code :
<tr
v-for="n in node.children"
track-by="id"
v-on:click="toggleElement(n)"
v-bind:class="{'active': n.selected}">
<td>
<i class="icons">
<i class="folder yellow icon"></i>
</i>
</td>
<td><a v-on:click.stop="getLevel(n.id)">{{ n.name }}</a></td>
<td><span v-if="n.modification_date">{{ n.modification_date | moment "calendar"}}</span><span v-else>-</span></td>
<td><span v-if="n.size">{{ n.size }}</span><span v-else>-</span></td>
And for the javascript method
toggleElement: function(element) {
element.selected = !!(element.selected === undefined || !element.selected);
},
Now some more details, the objects are being retrieved by an ajax call, and the selected property doesnt exist from the start.
Any advice or solution ?
Thanks a lot!
by default,vue.js can not track the property you add after vue instance had been created
BUT,there is some method you can call to tell vue that new properties been added:
vm.$set('selected', true) //this will make "selected" propertie
trackable
First, do not forget to add the closing </tr> in your code.
Second, you can not add new attributes on objects after creating them with VueJS.
If when creating the element, its attribute selected was undefined, then VueJS will not add the getter/setter on it and changing it won't update the interface.
You will need to add the selected attribute before passing it to VueJS.

alternating class in ng-repeat using scope var without binding

I have a nested ng-repeat on a table. It is an accordion table with child rows for each parent row. In order to accomplish this I created a <tbody> for each parent item, placing the parent row in a <tr> and then using ng-repeat to add all the child rows. Due to the multiple <tbody> elements the zebra striping on the table gets thrown off. Another wrinkle is that the table has the ability to collapse/expand child rows and I need the striping to be correct for whichever rows are visible. So I am trying to manually add striping classes. I'm using Angular's ng-init to toggle a scope variable, and then using ng-class to apply it. The problem is that it appears to be bound to the final state of the variable rather than what it was as the iterator was rendering the row.
HTML:
<tbody ng-repeat="parentRow in myData" ng-init="changeRowClass($even)">
<tr ng-class="{'industry-payments-even-row':industryRowEven,'industry-payments-odd-row':!industryRowEven}">
<td>{{parentRow.industryCode}} - {{parentRow.industryCodeDescription}}</td>
<td class="numeric">{{parentRow.ValueOneSum}}</td>
<td class="numeric">{{parentRow.ValueTwoSum}}</td>
</tr>
<tr ng-repeat="childRow in parentRow.childIndustries" ng-init="changeRowClass($even)" ng-class="{'industry-payments-even-row':industryRowEven,'industry-payments-odd-row':!industryRowEven}">
<td>{{childRow.industryCode}} - {{childRow.industryCodeDescription}}</td>
<td class="numeric">{{childRow.ValueOne}}</td>
<td class="numeric">{{childRow.ValueTwo}}</td>
</tr>
</tbody>
Controller code:
$scope.industryRowEven = false;
$scope.changeRowClass = function(isEven) {
$scope.industryRowEven = isEven;
};
I need each iteration (of parent OR child) to reverse the class for the next one (I'm leaving out the issue of if the child is visible or not for now to keep this more simple). I can see in the debugger that the variable is getting toggled properly on each iteration. The problem is that the ng-class seems to be bound to the current state in scope so when it is true it would apply one class, but then next time it is false and switches the class for all of them.
I need it to just print the class according to the variable state at the time it renders that row, and then ignore the variable unless the ng-repeat is started over (like for sorting or toggling visibility, etc.)
Is there a way to stop the binding?
AngularJS has this build in with directives called ngClassOdd and ngClassEven.
They work just like ngClass, but only on odd/even items inside an ngRepeat.

Passing a variable into the standard filter using angularJS

So I am trying to create a filter that works the same way as the built in angular filter in HTML but takes in a variable instead of a specific value.
E.g. In my html file I have something like this:
<tr ng-repeat = "item in Items | filter:{function:'1300'}">
<td>[[item.name]]</td>
</tr>
but I want to be able to pass in a variable instead of '1300' whose value is defined when the user clicks on a button (the button is linked to a specific value).
I was trying to recreate the built in filter function in a filter.js file and call it in my controller to no avail.
Any help would be appreciated!
You could do something like this jsBin:
<tr ng-repeat = "item in Items | filter:{function:theFilter}">
<td>{{item.name}}</td>
</tr>
And have your buttons like this:
<button ng-click="setFilter(1300)">1300</button>
<button ng-click="setFilter(1400)">1400</button>
<button ng-click="setFilter(1200)">1200</button>
And your controller method like this:
$scope.setFilter = function(filter) {
$scope.theFilter = filter;
}

Categories

Resources