Reputation: 956
I have a "tags" component variable that generates a whitelist and a blacklist. Currently, I have a updateTagLists() function which will update the respective whitelist and blacklist but I have to make sure this function is called when necessary in order for the whitelist/blacklist to properly update. This seems counter-intuitive and feels incorrect. What's the correct way of having this.whitelist and this.blacklist automatically update when this.tags changes? Posted below is my component.
import { Component, OnInit } from '@angular/core';
import { Tag } from '../../models/tag';
import { TagService } from '../../services/tag.service';
@Component({
selector: 'app-admin',
templateUrl: './admin.component.html',
styleUrls: ['./admin.component.css']
})
export class AdminComponent implements OnInit {
tags: any;
whitelist: Tag[];
blacklist: Tag[];
constructor(
private tagService: TagService
) {}
ngOnInit() {
this.tagService.getTags(1).then((tags) => {
this.tags = tags;
this.updateTagLists
});
}
updateTagLists() {
this.whitelist = this.tags.filter((tag: Tag) => tag.isWhitelisted );
this.blacklist = this.tags.filter((tag: Tag) => !tag.isWhitelisted );
}
whitelistAll() {
// Todo: Is there a better way of doing this where we aren't specifying the exact keys needed?
let updatedTags = this.tags.filter((tag) => !tag.isWhitelisted)
updatedTags = updatedTags.map((tag) => {
return { id: tag.id, name: tag.name, isWhitelisted: true, updated: true }
});
this.tags = updatedTags.concat(this.tags.filter((tag) => tag.isWhitelisted));
this.updateTagLists();
}
blacklistAll() {
// Todo: Is there a better way of doing this where we aren't specifying the exact keys needed?
let updatedTags = this.tags.filter((tag) => tag.isWhitelisted);
updatedTags = updatedTags.map((tag) => {
return { id: tag.id, name: tag.name, isWhitelisted: false, updated: true }
});
this.tags = updatedTags.concat(this.tags.filter((tag) => !tag.isWhitelisted));
this.updateTagLists();
}
handleToggle(event) {
if (!event) return;
let foundTag = this.tags.find( (tag) => event.id === tag.id );
foundTag.isWhitelisted = !event.isWhitelisted;
foundTag.updated = true;
this.updateTagLists();
}
}
Upvotes: 1
Views: 922
Reputation: 39432
The best way is to just deal with one tags
array and then do the needful based on that.
I've updated your whiteListAll
, blackListAll
, and handleToggle
methods.
import { Component } from '@angular/core';
import { TagService } from './tag.service';
export interface Tag {
id: number;
name: string;
isWhitelisted: boolean;
updated: boolean;
}
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
tags: Tag[];
get whiteListedTags() {
return this.tags.filter(tag => tag.isWhitelisted);
}
get whiteBlackTags() {
return this.tags.filter(tag => !tag.isWhitelisted);
}
constructor(private tagService: TagService) {}
ngOnInit() {
this.tagService.getTags(1).then((tags) => {
this.tags = tags;
});
}
whitelistAll() {
this.tags = [...this.tags.map(tag => ({...tag, isWhitelisted: true, updated: true}))];
}
blacklistAll() {
this.tags = [...this.tags.map(tag => ({...tag, isWhitelisted: false, updated: true}))];
}
handleToggle(index) {
this.tags[index].isWhitelisted = !this.tags[index].isWhitelisted;
}
}
In your template, you can check if a Tag
is whitelisted by checking if it's isWhitelisted
property is true
.
Optionally, you can also create getters
for getting Blacklisted and Whitelisted tags as I've done above.
Here's a Sample StackBlitz for your ref.
Upvotes: 1
Reputation: 5040
I don't completely understand the question, but if you want to perform some action on change of tags
. then create a setter function for it, so that the this.tags are updating only through this function.
setTags(tags) {
this.tags = tags;
this.updateWhitelist();
this.updateBlacklist();
}
From the code it seems that tags are only getting changed from onInit() function. But if you want to make the tags as input() then
private _tags;
@Input()
set tags(tags) {
this._tags = tags;
this.updateWhitelist();
this.updateBlacklist();
}
get tags() {
return tags;
}
Upvotes: 1
Reputation: 894
You would use a setter on your tags
variable.
Here's an example:
...
private _tags: any;
set tags(someTags: any) {
this._tags = someTags;
this.updateTagLists();
}
get tags(): any {
return this._tags;
}
...
This will run the set function when the value is updated. The set function will set a private var that holds the current tags value and it will make a call to update the other lists. The getter gets the value from the private var and returns it.
Upvotes: 1
Reputation: 56966
Instead of using a function like this:
updateTagLists() {
this.whitelist = this.tags.filter((tag: Tag) => tag.isWhitelisted );
this.blacklist = this.tags.filter((tag: Tag) => !tag.isWhitelisted );
}
Just use 2 TypeScript getters like this:
get whitelist() {
return this.tags.filter((tag: Tag) => tag.isWhitelisted )
}
get blacklist() {
return this.tags.filter((tag: Tag) => !tag.isWhitelisted )
}
You can reference them in your HTML like this:
{{ whitelist | json }} {{ whitelist.length }}
{{ blacklist | json }} {{ blacklist.length }}
Or in your controller like this:
console.log(this.whitelist)
console.log(this.blacklist)
And they will always be 100% accurate. No need to worry about calling a function at the right time to keep their values updated.
Upvotes: 1