Angular Like Counter - html

I wish to make a counter of like on Angular. If there is more like than disklike the square is green and vice versa (see stackblitz link).
Link:
enter link description here
My code seems fair, I debugg with consol.log and alert but without success.
If you can help me, give me advice and enlighten me it would be a great help.
Thank you in advance,
Valentin

Along with the code link, please try providing the question code in your question itself.
In your code if you would modify your result() method to this, you would get the desired output:
result() {
if (this.nbrLove > this.nbrDontLove) {
return 'green';
} else if (this.nbrLove < this.nbrDontLove) {
return 'red';
}
}
Also, there is no need of returning values from nbrL() and nbrD() methods.
As methioned out in a comment by #Ploppy if would bind a variable to the tenplate, it will be more effecient.
You can do this by calling result() in both nbrL() and nbrD() and binding the background style with a class variable:
export class AppComponent {
nbrLove = 0;
nbrDontLove = 0;
bckColor = 'white'
nbrL() {
this.nbrLove = this.nbrLove + 1;
this.result()
}
nbrD() {
this.nbrDontLove = this.nbrDontLove + 1;
this.result();
}
result() {
if (this.nbrLove > this.nbrDontLove) {
this.bckColor = 'green';
} else if (this.nbrLove < this.nbrDontLove) {
this.bckColor = 'red';
}
else {
this.bckColor = 'white';
}
}
}
<div
[ngStyle]="{'width': '20px',
'height': '20px',
'background-color': bckColor}">
https://stackblitz.com/edit/angular-catcjl?file=src%2Fapp%2Fapp.component.html

Related

Navigation Menu: Alternating colors for badges (colors should be in sequential order)

This is the function defined in MainService.ts, it can change the color set in badgesColorSet ,I have 3 colors defined in the json config already and i want these 3 colors to change everytime I open the website lets it is red then i refresh the page it should be green and then i refresh again it should be blue. so is this function correct and should i use for loop ?and I think i need to divide it by something so it increments and goes from 0 ,1 ,2 as index?
getIteriateColor(){
//gets color out of color set from turnkey.config file for badges
let badgesColorSet = 0; badgesColorSet < Array.length; badgesColorSet++;
console.log(badgesColorSet);
return badgesColorSet;
the colors are defined in turnkey-config.json
"badgesColorSet":["#ffff00","#f51307","#0cc902"],
this code is in the mainservice to define the background color of the material badge
badge: {bg: this.getNextColor() , fg: 'white' , title: moduleBadge},
Assuming getNextColor() calls getIteriateColor() to get the next color.
On getIteriateColor() let's loop through "badgesColorSet":["#ffff00","#f51307","#0cc902"] and starting again from [0] when iterate reaches [2].
To remember what color was last used we should store it somewhere on the client where the state remains (e.g localStorage), that way we know what color to choose next.
#Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
})
export class AppComponent {
badgesColorSet = ['#ffff00', '#f51307', '#0cc902'];
badgesColorSelected: string;
constructor() {
this.getIteriateColor();
}
getIteriateColor() {
// if there is no color in localStorage, set the first color
if (!localStorage.getItem('badgesColorSelected')) {
localStorage.setItem('badgesColorSelected', this.badgesColorSet[0]);
} else {
// if there is color, select the next color
const storageColor = localStorage.getItem('badgesColorSelected');
const colorIndex = this.badgesColorSet.indexOf(storageColor);
if (colorIndex + 1 > this.badgesColorSet.length - 1) {
this.badgesColorSelected = this.badgesColorSet[0];
localStorage.setItem('badgesColorSelected', this.badgesColorSet[0]);
} else {
this.badgesColorSelected = this.badgesColorSet[colorIndex + 1];
localStorage.setItem('badgesColorSelected',this.badgesColorSet[colorIndex + 1]
);
}
}
}
}
Working example: https://stackblitz.com/edit/angular-ivy-mw7s49?file=src%2Fapp%2Fapp.component.ts
Or for backend something similar except without localStorage.
badgesColorSet: string[] = ['#ffff00', '#f51307', '#0cc902'];
badgesColorSelected: string;
getIteriateColor() {
if (!this.badgesColorSelected) {
this.badgesColorSelected = this.badgesColorSet[0];
} else {
let nextColorIndex = 0;
for (let i = 0; i < this.badgesColorSet.length; i++) {
if (this.badgesColorSet[i] === this.badgesColorSelected) {
if (i <= this.badgesColorSet.length - 2) {
nextColorIndex = i + 1;
break;
}
}
}
this.badgesColorSelected = this.badgesColorSet[nextColorIndex];
}
console.log('current color is: ', this.badgesColorSelected);
}
badge: {bg: badgesColorSelected , fg: 'white' , title: moduleBadge},
I think the best way is to use [ngClass] and condition by pointing to the css classes that you have predefined with those colors.
In Component:
interface Link {
label: string;
route: string;
icon: string;
}
links: Link[] = [ // your links ]
Inside Template:
<nav>
<a *ngFor="let link of links; let odd = odd" [href]="link.route" [class.odd]="odd">{{link.label}}</a>
</nav>
If you want to "make something" when you refresh, you use localstorage I imagine you can use some like
color
badgesColorSet=["#ffff00","#f51307","#0cc902"]
ngOnInit(){
let index=localStorage.getItem('indexColor')!=undefined?
+localStorage.getItem('indexColor'): -1
index=(index+1)%3;
localStorage.setItem('indexColor',''+index)
this.color=this.badgesColorSet[index]
}
See that at first, if not exist localstorage.getItem('indexColor') (that's undefined) You makes index=0 and store "0", the next time you store "1","2","0","1","2"... -localStorage only admit "strings" it's because you use ''+index to convert to string and +localStorage.getItem('indexColor') to conver to number
The use of ìndex=(index+1)%3 makes that the value of index becomes 0,1,2,0,1,2,0,1,2...
NOTE: You can use also sesionStorage (Just replace in code localstorage by sessionStorage)
this is for the function i did some change to Joosep.P thanks to him .
getIteriateColor() {
if (!this.badgesColorSelected) {
this.badgesColorSelected = 0;
} else {
const colorIndex = this.badgesColorSelected;
if (colorIndex + 1 > this.badgesColorSet.length - 1) {
this.badgesColorSelected = this.badgesColorSet[0];
} else {
this.badgesColorSelected = this.badgesColorSet[colorIndex + 1];
}
}
console.log('current color is: ', this.badgesColorSelected);
return this.badgesColorSelected;
}
}
this is for the config
"badgesColorSet":["#f51307","#0cc902","#ffff00","#03fcf8","#03fcb1"],

Typescript conditional code is running regardless of confirm() value

I am trying to implement a dialogue box that confirms with the user if they want to continue with an action.
deleteItem(index: number): void {
let response = window.confirm("Are you sure?");
if (response) {
// delete item code
this.item.splice(index,1);
console.log("A");
} else {
console.log("B");
}
}
When I click the deleteItem button to trigger the dialogue, it deletes the item regardless but prints the correct console.log() string. Can anyone help me understand why this is happening and how to correct this?
Are you sure? "Ok" => deletes the item and logs "A" in console.
Are you sure? "Cancel" => deletes the item and logs "B" in console.
Unaltered code:
deleteItem(index: number): void {
let response = window.confirm("Are you sure?");
if (response) {
// delete feedback in students' boolean feedback arrays
for (var i = 0; i < this.csvRecords.length; i++) {
if (this.students[i].feedbackBoolean[index] == true) {
// add deduction value to student grade before delete
var newGrade = parseFloat(this.students[i].grade) + this.feedback[index].deduction
this.students[i].grade = newGrade.toString();
}
this.students[i].feedbackBoolean.splice(index,1);
}
// remove 1 element at index
this.feedback.splice(index,1);
console.log("A");
} else {
console.log("B");
}
}
I added the unaltered code to see if there is anything that could elicit this behavior that I might be overlooking. Thanks in advance.
Please forgive me for using javascript to implement your example, but I found that it seems that there is no problem. Can you provide a reproducible example?
const items = [0, 1, 2, 3, 4];
const deleteItem = (index) => {
let response = window.confirm("Are you sure?");
if (response) {
// delete item code
items.splice(index, 1);
console.log("A");
} else {
console.log("B");
}
}
deleteItem(0);
console.log(items);

why does it take two clicks for the DOM view to appear

0
this is my code now
template file:
<quill-view-html [content]="question.questionText" format="html" theme="snow" [id]="question.id" [change]="loadAnswer(studentAnswer)"
.ts file:
loadAnswer(studentAnswer) {
if (document.getElementById(question.id)) {
let inputs =
document.getElementById(question.id).getElementsByTagName('input') || [];
inputs.forEach((input, index) => {
input.value = studentAnswer[index]
})
}
}
the answer gets display in the input box but i am not able to type a new answer over it since the previous answer gets coming back. Any solution to this?
Firstly, let's make your code more pretty.
loadAnswer(studentAnswer){
if (document.getElementById(question.id)) {
let inputs = document.getElementById(question.id).getElementsByTagName('input') || [];
inputs.forEach((input, index) => {
input.value = studentAnswer[index]
})
}
}
Can you share your template code with us? Function looks good.

How to change Background image every x amount of seconds

I'm pretty new to Angular and programming in general.
I wanted to change the background image of my Page by using the setInterval method. It should change every second but for some reason, it changes much faster.
Component:
export class AppComponent implements OnInit {
images: Image[] = [];
changeBackgroundCounter = 0;
constructor(private imagesService: ImagesService) {}
getImage() {
setInterval(() => {
this.changeBackgroundCounter = this.changeBackgroundCounter + 1;
if (this.changeBackgroundCounter > this.images.length - 1) {
this.changeBackgroundCounter = 0;
}
}, 1000);
return this.images[this.changeBackgroundCounter].image;
}
ngOnInit() {
this.images = this.imagesService.getImages();
console.log(this.images[0]);
}
}
Template:
<div [ngStyle]="{'background-image': 'url('+ getImage() + ')'}" [ngClass]="{imageBackground: getImage()}">
Stackblitz link
In your template, you have
<div [ngStyle]="{'background-image': 'url('+ getImage() + ')'}" [ngClass]="{imageBackground: getImage()}">
This means angular keeps calling the getImage() method to find out what the background should be. This will happen very frequently. Each time the method is called, a new interval is created, so there end up being loads of them. You can see this by putting a line of logging within your interval and you will see how often it's being triggered.
setInterval(() => {
console.log('interval triggered'); // <------- add this line to see how often this code is running
this.changeBackgroundCounter = this.changeBackgroundCounter + 1;
if (this.changeBackgroundCounter > this.images.length - 1) {
this.changeBackgroundCounter = 0;
}
}, 1000);
To fix your problem, you need to call getImage() only once, which can be done within ngOnInit(). The template can get the image from images[this.changeBackgroundCounter].image.
You're complicating your code for nothing. Create a variable, equal to a string, and assign it a new value every X seconds in your ngOnInit() !
Then set the background image equals to that variable, and voilà !
Here is what it look like in code :
export class AppComponent implements OnInit {
images: Image[] = [];
actualImage: string;
changeBackgroundCounter = 0;
constructor(private imagesService: ImagesService) {}
ngOnInit() {
this.images = this.imagesService.getImages();
this.actualImage = this.images[0].image;
setInterval(() => {
this.changeBackgroundCounter++;
if (this.changeBackgroundCounter > this.images.length - 1) {
this.changeBackgroundCounter = 0;
}
this.actualImage = this.images[this.changeBackgroundCounter].image;
}, 5000);
}
}
I kept as much as possible of your inital code. My new variable is called actualImage, I set a default value in my ngOnInit, right after you get all your images from your service.
Then I call setInterval and set a new value to actualImage every 5 seconds !
https://stackblitz.com/edit/angular-setinterval-f5bghq
CARE: When using setInterval, be used to clear it on ngOnDestroy(), it can lead to some weird bugs you don't want to get involved in.
Simply create an other variable, type any, and do the following :
this.interval = setInterval(() => {...})
ngOnDestroy() {
clearInterval(this.interval);
}

Aurelia update value of bound item in another class

I guess the question boils down how to i pass the instance of a property to another class.
I have something like this:
import timerClass from "./timer";
export class App {
constructor() {
this.timeLeft = 6; //<--- I want to update this
new timerClass(this.timeLeft);
}
activate() {
}
}
and
export default class {
constructor(time) {
this.initialTime = time;
setInterval(function () {
if (--time < 0) {
time = this.initialTime; //<--- From here
}
}, 1000);
}
}
Time is passed in but not reflected in the view when updated.
In knockout this was easy as all observables are functions an I could pass it round all over the place. How would i do the same here, should I wrap it in a function too?
When you call
new timerClass(this.timeLeft);
you pass your variable by value, i.e. the timer just gets 6 and there is no way to modify it there. The easiest way to fix this is indeed pass the callback function. I made it work with the following code.
timer.js:
export default class {
constructor(time, callback) {
this.initialTime = time;
this.currentTime = time;
setInterval(() => {
if (--this.currentTime < 0) {
this.currentTime = this.initialTime;
}
callback(this.currentTime);
}, 1000);
}
}
app.js:
constructor(){
this.timeLeft = 6;
var timer = new timerClass(this.timeLeft, v => this.timeLeft = v);
}
So I did some more reading and came across the aurelia-event-aggregator
http://aurelia.io/docs#the-event-aggregator
This allowed me to try a different angle. As my timer is eventually going to become a game loop this pub/sub way of doing it will work quite nicely.
Im still quite green with the syntax so I imagine its doing some things not entirely "best practice" but hope it helps someone.
main.js
import {inject} from 'aurelia-framework';
import {EventAggregator} from 'aurelia-event-aggregator';
import TimerClass from "./timer";
#inject(EventAggregator)
export class Main {
constructor(eventAggregator) {
this.eventAggregator = eventAggregator;
this.timer = new TimerClass(this.eventAggregator);
this.eventAggregator.subscribe('gameLoop', currentTime => {
this.timeLeft = currentTime
});
}
activate() {
this.timer.start();
}
}
timer.js
export default class Timer {
constructor(eventAggregator) {
this.eventAggregator = eventAggregator;
}
start(){
var initalTime = 5;
var currentTime = initalTime;
setInterval(() => {
if (--currentTime < 0) {
currentTime = initalTime;
}
this.eventAggregator.publish('gameLoop', currentTime);
}, 500);
}
}
main.html
<template>
<div>
<h2>Time Left:</h2>
<div>${timeLeft}</div>
</div>
</template>