I am using angular 2 and I have two buttons I want toggle class between two buttons but. Below is my code
<button class="btn rounded" [ngClass]="{'btn-default': !clicked, 'btn-primary': clicked}" (click)="clicked = !clicked">
<i class="fa fa-long-arrow-up"></i>
</button>
<button class="btn rounded" [ngClass]="{'btn-default': !clicked, 'btn-primary': clicked}" (click)="clicked = !clicked">
<i class="fa fa-long-arrow-down"></i>
</button>
My problem is I want to toggle class but at time only one button can select and other condition is both buttons can be deselect. On click of one button other button should be deselect and once you click on selected button that button should be deselect and I want to do this only using buttons. Please help
You can use this pattern which will work for any number of buttons:
In your controller, set up an array of buttons and a selectedButton variable
buttons= [
{class: "fa fa-long-arrow-up", name: "button1"},
{class: "fa fa-long-arrow-down", name: "button2"},
]
selectedButton;
toggleSelect(button) {
if (button == this.selectedButton) {
this.selectedButton = undefined
} else {
this.selectedButton = button
}
}
Then in your template populate the selectedButton on click, and set your class based on whether it is selected
<button *ngFor="let button of buttons" class="btn rounded" [ngClass]="(selectedButton == button) ? 'btn-primary' : 'btn-default'" (click)="toggleSelect(button)">
<i [class]="button.class"></i>
</button>
This way you could have any number of buttons and only one will ever be "selected" at a time
working example: https://stackblitz.com/edit/angular-v9zlaz?file=src%2Fapp%2Fapp.component.html
Related
This is my function that takes the id from my button and changes the text:
var modal_button_update = document.getElementById("modal_button_text");
if (modal_button_update.innerHTML === "Add") { modal_button_update.innerHTML = "Update"; }
It's working fine with this button (Add becomes Update)
<button type="button" class="btn btn-primary save_button add_group" id="modal_button_text">Add</button>
But for some reason it does not change anymore if I try to add a font awesome icon:
<button type="button" class="btn btn-primary save_button add_group" id="modal_button_text"><i class="fas fa-save" aria-hidden="true"></i>Add</button>
What could be the cause?
I ran your code. It seems the problem is that you are checking if your modal_button_update button's innerHTML is equal to Add. The original button:
<button type="button" class="btn btn-primary save_button add_group" id="modal_button_text">Add</button>
works because the innerHTML of your modal_button_update is exactly 'Add', but your modified modal_button_update: <button type="button" class="btn btn-primary save_button add_group" id="modal_button_text"><i class="fas fa-save" aria-hidden="true"></i>Add</button> does not work because the innerHTML is <i class="fas fa-save" aria-hidden="true"></i>>Add which is not equal (===) to 'Add'.
Here's three different ways I chose to solve this issue:
Remove the <i class="fas fa-save" aria-hidden="true"> element and place the font-awesome icon inside the button class like: <button type="button" class="btn btn-primary save_button add_group fas fa-save" id="modal_button_text">Add</button>
`
Alter your Javascript to look something like: var modal_button_update = document.getElementById("modal_button_text"); if (modal_button_update.innerHTML.includes("Add")) { modal_button_update.innerHTML = "Update"; }
Here the button checks to see if the innerHTML contains 'Add'.
Keeping the font-awesome icon:
In the two solutions above, your Javascript code will strip the button element of the font-awesome class when successfully changing the innerHTML to 'Update'. It is, imo, easier to use jQuery to alter the value of the button to solve this issue like:
---HTML---
<button type="button" class="btn btn-primary save_button add_group" id="modal_button_text"><i class="fas fa-save" aria-hidden="true"></i>Add</button>
---Javascript--
if ($('#modal_button_text').html().includes("Add")) {
$('#modal_button_text').html("Update");
}
If your intent is to keep the icon no matter the state of the text (i.e., Add or Update), I would personally enclose the word "Add" in a span as follows:
HTML:
<button type="button" class="btn btn-primary save_button add_group" id="modal_button_text"><i class="fas fa-save" aria-hidden="true"></i><span id="modal_button_span">Add</span></button>
Then it is just a matter of whether you use jQuery or not as to which of the following will work for you.
JavaScript:
Change value based on current text:
if(document.getElementById("modal_button_span").innerHTML === "Add") document.getElementById("modal_button_span").innerHTML = "Update";
Toggle value when the button is clicked based on current text:
document.getElementById("modal_button_span").innerHTML = document.getElementById("modal_button_span").innerHTML === "Add" ? "Update" : "Add";
jQuery:
Change value based on current text:
if($("#modal_button_span").html() === "Add") $("#modal_button_span").html("Update");
Toggle value when the button is clicked based on current text:
$("#modal_button_span").html($("#modal_button_span").html() === "Add" ? "Update" : "Add");
By enclosing the word Add in a span, you are free to do whatever you need to the text without disrupting the rest of the button or save icon.
I have an array of objects with delete button hidden when page loads. Now I want to show the delete button when new object is pushed to the array, the existing objects button should still remain hidden. How do I hide existing buttons and only show new object delete button.
html
<div>
<table >
<tr>//.....</tr>
<tr *ngFor="list of Array1">
<td><button type="button" class="btn btn-danger"
(click)=remove(i) [disabled]="disabled">
<i class="glyphicon glyphicon-remove"></i>
</button></td>
<td>{{list.type}}</td>
<td>{{list.year}}</td>
</tr>
</table>
</div>
<div>
<table >
<tr>//.....</tr>
<tr *ngFor="list of Array2">
<td><button type="button" class="btn btn-secondary"
(click)=addObj(i)>
<i class="glyphicon glyphicon-plus"></i>
</button></td>
<td>{{list.type}}</td>
<td>{{list.year}}</td>
</tr>
</table>
</div>
Here is the code used for adding new object from another array:
ts
//..
disabled = false;
....
addObj(index) {
// is there a way I can enable the delete button of just the index pushed?
this.Array1.push(this.List[index]);
this.List.splice(index, 1)
}
Define a variable to show/hide the button
isDisabled = true;
Then change the variable state in your code where you are pushing new items to the array. It could be any method or inside subscriber etc.
this.isDisabled = false; // or this.isDisabled = !this.isDisabled;
then in your button bind disabled attribute with this isDisabled variable.
[disabled]="isDisabled"
Complete Button Example
<button (click)="delete(item.id)" [disabled]="isDisabled">Delete</button>
try this
<button type="button" class="btn btn-danger"
(click)=remove(i) [disabled]="!show">
<i class="glyphicon glyphicon-remove"></i>button
</button>
//..
show = false;
....
addObj(index) {
// is there a way I can enable the delete button of just the index pushed?
this.Array1.push(this.List[index]);
this.show = true;
this.List.splice(index, 1)
}
Create a dummy array containing the index of newly added object. And then make condition on that array in *ngIf.
Html
<button type="button" class="btn btn-danger"
(click)=remove(i) *ngIf="deleteButtonShowIndex.indexOf(i) !== -1">
<i class="glyphicon glyphicon-remove"></i>
</button>
Component
deleteButtonShowIndex = [];
addObj(index) {
deleteButtonShowIndex.push(index);
this.Array1.push(this.List[index]);
this.List.splice(index, 1)
}
The better approach I will suggest is to maintain a flag in this.Array1 as shown below:
this.Array1 = [{
show: false,
data: {}
},
{
show: false,
data: {}
},
{
show: true,
data: {}
}
];
Declare a property showButton which will be used to decide whether button will be displayed or not. And when you insert a new record make this showButton property to true which will lead to show the button like shown in the demo. Then in your template you can easily use *ngIf to decide whether to show the button or not.
app.component.html
<button (click)="addButtonHandler()">
add record
</button>
<table >
<tr>
<th>Name</th>
<th>Action</th>
</tr>
<tr *ngFor = "let val of item">
<td>{{val.name}}</td>
<td *ngIf="val.showButton"><button>click me</button></td>
</tr>
</table>
app.component.ts
name = 'Angular';
item:Item[]=[]
constructor(){
this.item.push({
'name':'Monica',
'showButton':false
})
this.item.push({
'name':'Rachel',
'showButton':false
})
}
addButtonHandler(){
this.item.push({
'name':'phoebe',
'showButton':true
})
}
Working demo: link
I am needing to have a dropdown box that sits above a Ngx-datatable and that dropdown box needs to sort the Ngx-datatable by the values in the dropdown box. I am still new to Angular, so as I discovered that it is wrong to have the ngx-datatable in the component.html. How might I bootleg the datatable so that I can sort the rows by the values in the dropdown box?
Thinking that the method in the component.ts was linked to the datatable I was going to call that method in the dropdown box to sort it. It is completely separate!
component.html
<ngx-datatable class="expandable"
[rows]="rows"
[columns]="columns"
[headerHeight]="40"
[rowHeight]="'auto'"
[columnMode]="'force'" [limit]="20" [footerHeight]="50">
<ngx-datatable-column name="Header">
<ng-template let-value="value" let-row="row" ngx-datatable-cell-template>
<span class="custom-cell"><a (click)="method(content, id, false)">{{value}}</a></span>
</ng-template>
</ngx-datatable-column>
My dropdown box
<div ngbDropdown class="filter-dropdown-wrapper">
<button class="btn btn-light filter-button" id="input1" ngbDropdownToggle>Select an option</button>
<div ngbDropdownMenu aria-labelledby="inputmethod">
<!--<select (change)="getColumnNames($event.target.value)">
<option *ngFor="let element of rows" value="{{element.header}}"></option>
</select>-->
component.ts
columns = [
{ prop: 'header', name: 'Header' },
{ prop: 'notrelavant', name: 'Not Relevant' }, ];
What I need is: On click of the header value in dropdown box sort the datatable.
I have came up with a solution for yours. It is actually not very difficult if we break down the steps:
1) On the ngbDropdown, we populate the menu items with the columns of the datatable. we attach a click event binding on each individual menu items, and we bind them to the sort() method, which takes in the column property (column.prop) as a parameter.
<div ngbDropdown class="d-inline-block">
<button class="btn btn-light filter-button" id="input1" ngbDropdownToggle>Select an option</button>
<div ngbDropdownMenu aria-labelledby="inputmethod">
<button ngbDropdownItem *ngFor="let column of columns" (click)="sort(column.prop)">
{{ column.prop }}
</button>
</div>
</div>
2) Now, on our component.ts, we define our sort() method. rows represent the data in the datatable. We use localeCompare
to sort it in alphanumerical order. We create a shallow copy of rows to explicitly trigger change detection within the datatable to update the order of the data.
sort(prop) {
this.rows.sort((a, b) => a[prop].localeCompare(b[prop], 'en', { numeric: true }));
this.rows = [...this.rows];
}
I have created a working demo over here. Hope it helps in my explanation!
I want to generate and display as many buttons depending on the number of elements in my list. Can someone tell me how I can implement that?
Currently it is hardcoded like the below code. But often I only have a list with only button 1 and 2. And then I dont need the button 3 and button 4.
Thanks for your help!
list=[button1, button2, button3, button4]
<div class="tabs_item_categories">
<button class="tab_item_category" (click)="button1_active()">
Button1
</button>
<button class="tab_item_category" (click)="button2_active()">
Button2
</button>
<button class="tab_item_category"(click)="button3_active()">
Button3
</button>
<button class="tab_item_category" (click)="button4_active()">
Button4
</button>
</div>
You iterate with *ngFor structural directive in angular:
<div class="tabs_item_categories">
<button class="tab_item_category"
*ngFor="let buttonConfig of buttonConfigs"
(click)="buttonConfig.onClick()">
{{buttonConfig.label}}
</button>
</div>
and in your typescript:
buttonConfigs = [
{
label: 'Button 1',
onClick: this.doSomethingOnButton1Click
},
...
];
doSomethingOnButton1Click is lambda in the component.
"detail" in *ngFor is coming from the server and is it is containing a list.
and I am selecting a item from it. I want to to make that button active when
the user clicks it and it should remain active until the user selects another
option from the list. I am using [ngClass] but it is activating a button for 1 to 2 seconds.
<ion-list>
<button ion-item [ngClass]="configop.selection" *ngFor="let configop of detail" (click)="itemSelected(configop)" >
<div class="ion-item optionalItem">
<div class="ion-button">
<span class="color-code" >
<img src="{{configop.image}}">
</span>
<span class="color-name">{{ configop.name }}</span>
<span class="color-price">{{ configop.price|currency:'PKR':false }}</span>
</div>
</div>
</button>
</ion-list>
.ts file
itemSelected(configop: any) {
if(this.selection !=null){
if(configop.name == this.selection){
this.storage.remove('carPaint');
this.selection=configop.name;
}
else {
this.storage.remove('carPaint');
this.storage.set('carPaint', configop);
this.selection=configop.name;}
}
else {
this.storage.set('carPaint', configop);
this.selection=configop.name;}
}
Make a unique id to each button and assign the unique id to another variable and css class based on the selected id
<button (click)="active(1)" [ngClass]="{'activeclass': activebutton === 1 }" type="button">button1</button>
<button (click)="active(2)" [ngClass]="{'activeclass': activebutton === 2 }" type="button">button2</button>
Make a function to add the css class to the selected button
public activebutton: number;
active(buttonvalue: number) {
if (this.activebutton === buttonvalue) {
this.activebutton= 0;
}
else {
this.activebutton= buttonvalue;
}
}