How to switch status in Angular - javascript

I have select options that I need to select 1 option at the time and set active value of selected item to true
So far I can make that, but the issue is:
When I change my selected option, first option active will not be set to false
Screenshot
code
HTML
<ion-row>
<ion-col *ngFor="let imf of allImages" size="4">
<img [id]="imf.id" (click)="getName(imf)" [src]="imf.src" [alt]="imf.id">
</ion-col>
</ion-row>
Component
allImages = [{
'src' : '../../../assets/bgs/01.png',
'id' : '01',
'name': '01.png',
'active': false,
},
{
//and so on...
}];
getName(data) {
// add class to selected option
var titleELe = document.getElementById(data.id);
titleELe.classList.add('active');
// set active value of selected option to "true"
let index = this.allImages.indexOf(data.id);
data.active = true;
this.allImages[index] = data;
// issues:
// remove added class from old item
// remove "true" from old item
}
What I need
remove added class from old item
remove "true" from old item
Any idea?

Solved
here is my last update which fixed my issues
getName(data) {
const items = this.allImages.filter((item) => { // loop all items
if(item.active == true) { // if any of them is set active to true
item.active = false; // set it to flase
var titleELe = document.getElementById(item.id);
titleELe.classList.remove('active'); // and remove the class of it
}
});
var titleELe = document.getElementById(data.id);
titleELe.classList.add('active'); // add class to new selected item
const index = this.allImages.indexOf(data.id);
data.active = true; // set newly selected item active to true
this.allImages[index] = data;
}
Hope it can help others as well.

Try using ngClass for setting 'active' class
HTML
<ion-col *ngFor="let imf of allImages;let i=index" size="4">
<img [id]="imf.id" [ngClass]="{'active':currentItemIndex == i}"
(click)="setActiveItemIndex(i)" [src]="imf.src" [alt]="imf.id">
</ion-col>
TS:
//property
currentItemIndex=0;
setActiveItemIndex(i){
currentItemIndex=i;
}
In case in future you want to get the image which is active
const activeImage=this.allImages[currentItemIndex]

Related

display text based on the value returned by a class binded to a method

I am running a loop with each item that has a **button **that has a **class **that is **binded **to a method. i want to display a certain text for this button, depending on the value returned by the aforementioned method
HTML Template
<button v-for="(item, index) in items"
:key="index"
:class="isComplete(item.status)"
> {{ text_to_render_based_on_isComplete_result }}
</button>
Method
methods: {
isComplete(status) {
let className
// there is another set of code logic here to determine the value of className. below code is just simplified for this question
className = logic ? "btn-complete" : "btn-progress"
return className
}
}
what im hoping to achieve is that if the value of the binded class is equal to "btn-completed", the button text that will be displayed is "DONE". "ON-GOING" if the value is "btn-in-progress"
my first attempt was that i tried to access the button for every iteration by using event.target. this only returned undefined
another option is to make another method that will select all of the generated buttons, get the class and change the textContent based on the class.
newMethod() {
const completed = document.getElementsByClassName('btn-done')
const progress= document.getElementsByClassName('btn-progress')
Array.from(completed).forEach( item => {
item.textContent = "DONE"
})
Array.from(progress).forEach( item => {
item.textContent = "PROGRESS"
})
}
but this may open another set of issues such as this new method completing before isComplete()
i have solved this by returning an array from the isComplete method, and accessed the value by using the index.
<template>
<button v-for="(item, index) in items"
:key="index"
:class="isComplete(item.status)[0]"
:v-html="isComplete(item.status)[1]"
>
</button>
</template>
<script>
export default {
methods: {
isComplete(status) {
let className, buttonText
// there is another set of code logic here to determine the value of className. below code is just simplified for this question
if (className == code logic) {
className = "btn-complete"
buttonText = "DONE"
}
else if (className != code logic) {
className = "btn-progress"
buttonText = "ON-GOING"
}
return [ className, buttonText ]
}
}
}
</script>

Angular ngfor select all and deselect

I have items :
items: [
{name: 'Name'},
{name: 'Name'},
{name: 'Name'}
]
I am showing them in html :
<ion-checkbox (click)="click(); selectAllItems()" class="checkboxas" [(ngModel)]="allTobuli"></ion-checkbox>
<!-- this isnt in ngFor and it Selects all items -->
<ion-card *ngFor="let item of jsonObj" class="relative" (click)="compareTobuli(item,i);checkboxTobuli(item)">
<ion-checkbox (click)="compareTobuli(item,i)" [(ngModel)]="item.allTobuliItem" class="checkboxas absolut-check"></ion-checkbox>
</ion-card>
Each of them as you can see got checkbox - if you click on item it is added to another array and checkbox value becomes true. Another thing is that there is one checkbox out of ngFor which make another array same as items.
The problem is that I don't know how to change ngFor all checkboxes values when clicking on checkBox which isnt in ngFor.
I am using sets so it's my TS :
compareTobuli(item,i){
if (this.selected.has(item)) {
this.selected.delete(item);
console.log('Trinam', this.selected)
} else {
this.selected.add(item);
console.log('Pridedan', this.selected)
}
}
click() {
this.clicked = !this.clicked;
console.log(this.clicked);
return this.clicked;
}
selectAllItems() {
if(this.clicked == true) {
this.selected = new Set(this.jsonObj);
console.log(this.selected);
}
else {
this.selected = new Set;
console.log('deleted all', this.selected);
}
}
checkboxTobuli(item){
item.allTobuliItem = !item.allTobuliItem;
}
First of all:
Here is a working stackblitz that also select and deselect all values on click.
You already use (click)="click(); selectAllItems()" on your ion-checkbox to call click() and selectAllItems().
All you need to do is modifing the specific values (of the iterated items) inside these method.
selectAllItems() {
for(let i=0; i<this.jsonObj.length; i++) {
let item = this.jsonObj[i]; // this is your item from *ngFor="let item of jsonObj"
item.allTobuliItem = true; // select every single item
}
}
You need to update the value of allTobuliItem for each item in the jsonObj. Angular's data binding will take care of the rest. Example:
Template
<ion-checkbox
(click)="click(); selectAllItems()"
class="checkboxas"
[(ngModel)]="allTobuli"></ion-checkbox>
Component
public selectAllItems() {
this.jsonObj = this.jsonObj.map(item => {
item.allTobuliItem = this.allTobuli;
return item;
});
}

Angular2 Get component reference dynamically

I have multiple <mat-button-toggle> elements generated in my app and I want always only one selected. The problem that I now have is, how to get the component reference to the last selected toggle-button when another toggle button is clicked.
I really searched quite a while but couldn't understand how to do it.
component.html
<mat-button-toggle (click)="onKeywordSelect($event)" *ngFor="let keyword of keywords" [id]="keyword.id" [attr.id]="keyword.id" [value]="keyword.id" class="keyword">
<div class="text">{{ keyword.name }}</div>
</mat-button-toggle>
component.ts
// imports and #Component
export class NavbarComponent implements OnInit {
keywords = [new Keyword('name1'), new Keyword('name2')]; // sample data
$selectedKeyword: $ | any; // I've imported JQuery
onKeywordSelect(event: any) {
// This element depends on where you mouse was positioned when clicking
// Most often not the <mat-button-toggle> but some child element
const target = event.target;
// To get to the <mat-button-toggle> component that was clicked
const matButton = $(target).closest('mat-button-toggle');
if (this.$selectedKeyword !== undefined) {
// At the start there is no selected keyword
// TODO: Set the 'checked' property of the cur selected keyword to false
}
this.$selectedKeyword = $matButton;
}
}
I tried it with #ViewChild() but because the id of the selected keyword changes when the user selects one I don't know how to keep track of the selected component reference.
Edit
Forgot to mention: Yes I'm aware of mat-button-toggle-group but I don't want to use it because of some styling. Is there no other way to solve this?
Edit: Updated my ans as your requirement is not to use mat-button-toggle-group:
You can use checked property and set current and last selected value on change event like this:
component.html:
<mat-button-toggle
*ngFor="let keyword of keywords"
value="{{keyword.id}}"
[id]="keyword.id"
[attr.id]="keyword.id"
(change)="this.onChange(keyword.id)"
[checked]="this.currValue === keyword.id">
{{keyword.name}}
</mat-button-toggle>
<div class="example-selected-value">
Last Selected value: {{this.lastValue}}
</div>
<div class="example-selected-value">
Current Selected value: {{this.currValue}}
</div>
component.ts:
keywords: any = [
{id: 1, name: "name1"},
{id: 2, name: "name2"},
{id: 3, name: "name3"},
]
lastValue: string = "";
currValue: string = "";
onChange = (value) => {
this.lastValue = this.currValue;
this.currValue = value;
}
Check Demo Here.
Add mat-button-toggle-group to select only one button and get value of group to get last selected button
see: https://stackblitz.com/angular/yrqebgjbxao?file=app%2Fbutton-toggle-exclusive-example.ts

How to disable all parent and childs if one parent is selected?

Here in first condition i was able to disbale all parents except current parent that is selected.
checkbox.js
if (geoLocation.id === 5657){
var getParent = geoLocation.parent();
$.each(geoLocation.parent(),function(index,location) {
if (location.id !== geoLocation.id) {
var disableItemId = 'disabled' + location.id;
// Get **strong text**the model
var model = $parse(disableItemId);
// Assigns a value to it
model.assign($scope, true);
}
}
);
At this point i am trying to disbale all the child for the parents that are disabled in above condition. How to achieve that task with below code any help will be appreciated.
So far tried code...
$.each(geoLocation.parent().items,function(index,location) {
if(location.id !== geoLocation.id){
var disableItemId = 'disabled' + location.children.data;
// Get the model
var model = $parse(disableItemId);
// Assigns a value to it
model.assign($scope, true);
}
});
console.log(getParent);
}
If you plan to use angular, better express all of this in a model structure, and use ng-click and ng-disabled to achieve what you need.
Template:
<ul>
<li ng-repeat="item in checkboxes">
<input type="checkbox" ng-disabled="item.disabled" ng-click="disableOthers(item)"> {{item.name}}
</li>
</ul>
Controller:
$scope.disableOthers = function (item) {
// iterate over parents and childs and mark disabled to true
};

knockout: remove one element from multiselect control when other is selected

I'm using knockout and I have a list of item, let say:
Tomato,
Potato,
Broccoli,
Bean
all those item are allowed to user to select from multiselect form-control.
<select class="form-control" multiple
data-bind="selectPicker: Types,
optionsText: 'Name',
optionsValue: 'VegetableTypeId',
selectPickerOptions: { optionsArray: AvailableVegetableTypes }">
</select>
Except one scenario - when the user selects tomato, potato should unselect.
I was trying to use subscription on selected items array:
this.Types.subscribe(changes => {
var VegetableTypes = this.AvailableVegetablesTypes();
var company = VegetableTypes.First(element => element.VegetableTypeId == changes[0].value);
if (changes[0].status == "added") {
if (Vegetable.IsTomato) {
this.Types.remove(element =>
VegetableTypes.First(baseElement =>
baseElement.VegetableTypesTypeId == element && baseElement.IsPotato));
} else if (Vegetable.IsPotato) {
this.Types.remove(element =>
VegetableTypes.First(baseElement =>
baseElement.VegetableTypesTypeId == element && baseElement.IsTomato));
}
}
}, null, "arrayChange");
Problem is that I'm using ObservableArray.Remove, so it's again call my function before current run is finish. This should not be a problem, because after remove first change is "deletion" type, so whole logic should not be executed.
But after this, when I select tomato/potato again, nothing is fired. In the end I actually have both tomato and potato selected.
Then, when I deselect one of these two and select it again, everything works fine, and then the whole situation repeats.
Do you have any ideas?
I didn't understand why you are using selectPicker bindings instead of the normal options and selectedOptions bindings available in Knockout.
However, I built a simple demo which implements the desired behaviour. You can find it here:
http://jsbin.com/fofojaqohi/1/edit?html,js,console,output
Note that, whenever you select Tomato after Potato, Potato will become unselected.
You were on the right track: you need to subscribe to the array of selected items and check if there are any invalid selections. I hope this helps.
For reference, here is the code:
HTML:
<select class="form-control" multiple="true"
data-bind="options: availableVegetableTypes, selectedOptions: selected">
</select>
JS:
var availableVegetableTypes = ['Tomato',
'Potato',
'Broccoli',
'Bean'];
var selected = ko.observableArray();
var unselectMap = {
'Tomato': 'Potato'
};
selected.subscribe(function(selectedOptions){
var keysToUnselect = [];
console.log("Selected", selectedOptions);
selectedOptions.forEach(function(selectedOption){
if (unselectMap[selectedOption] != null) {
// This key exists in the unselect map
// Let's check if the value is in the array
if (_.contains(selectedOptions, unselectMap[selectedOption])) {
// The invalid key exists. Let's mark it for removal.
keysToUnselect.push(unselectMap[selectedOption]);
}
}
});
if (keysToUnselect.length > 0) {
console.log("Unselect", keysToUnselect);
var reject = function(v){
return _.contains(keysToUnselect, v);
};
filteredSelectedOptions = _.reject(selectedOptions, reject);
console.log("Filtered", filteredSelectedOptions);
selected(filteredSelectedOptions);
}
});
ko.applyBindings({
availableVegetableTypes:availableVegetableTypes,
selected: selected
});

Categories