Running a function before subscribing - javascript

I would like to add a form control as soon as the user has selected an option.
My select function:
selected(event: MatAutocompleteSelectedEvent): void {
this.setTechnologies = new Set();
this.setTechnologies.add(this.techInput.nativeElement.value);
}
Adding a new controller
this.primaryFormGroup.addControl('tech', new FormControl('', []));
this.primaryFormGroup.valueChanges.subscribe(inputFields => {
if (inputFields) {
inputFields.tech = Array.from(this.setTechnologies);
}
}
My problem is that the line inputFields.tech = Array.from(this.setTechnologies); will be executed, before the function selected() could be run. So in this case the value of inputFields.tech is ALWAYS empty.
How can I run the function first?

One approach is to add a slight delay to valueChanges. This ensures that selected() function is run before valueChanges.
this.primaryFormGroup.valueChanges.pipe(
delay(500)
).subscribe(inputFields => {
if (inputFields) {
inputFields.tech = Array.from(this.setTechnologies);
}
}

Related

LocalStorage drag previous saved array

I'm coding a currency converter that save every conversion that the user make and displayed. When i make the first conversion is fine. When i make the second it show the first one and the second, instead of only the second, like a to do list. Also i tried to use a constructor but i dont think that is the problem. If anyone can give me any help, that would be awesome!. Thx.
function calculo(){
resultado=(cantidad/monedaVal1)*monedaVal2;
$('#res').html('Obteniendo conversion...');
$('#res').fadeOut(500)
.fadeIn(500)
.fadeOut(500)
.fadeIn(500,function(){
$('#res').html(cantidad+' '+monedaText1+' = '+resultado.toFixed(2)+' '+monedaText2);
});
almacen();
}
class conversion {
constructor(monto, origen, destino, final) {
this.monto = monto;
this.origen = origen;
this.destino = destino;
this.final = final;
}
}
function almacen(){
cambios.push(new conversion(cantidad,monedaText1,monedaText2,resultado));
guardarCambio(cambios);
listarCambio(cambios);
}
function guardarCambio(cambios) {
let cambio = cargarCambio();
cambio.push(cambios);
localStorage.setItem('test', JSON.stringify(cambios));
}
function cargarCambio() {
if (localStorage.getItem('test')) {
return JSON.parse(localStorage.getItem('test'));
}
return [];
}
function listarCambio(cambios){
$.each(cambios, function (i) {
$('#conversiones').append('<tr><td>'+cambios[i].monto+'</td><td>'+cambios[i].origen+'</td><td>'+cambios[i].destino+'</td><td>'+cambios[i].final+'</td></tr>');
})
}

How can I see if my object updates in a loop?

I want this code to check if one of the keys in the "states" object updates from false to true, and if it does, then run the code inside of the if-statement. For some reason, even if I update the states variable manually (like I did here). The code never runs.
I'm using the "compareMe" variable to hold the last version of the "states" object by setting it equal to the "states" object at the end of the loop.
I'm sure this is not the best approach, any ideas would help a ton.
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms * 1000)
})
}
var states = { Dad: false, Mom: false, Brother: false, Sister: true }
var compareMe = {}
var loop = 0;
(async () => {
while(true) {
loop++
if (loop === 5) {
states.Dad = true
}
for (const key of Object.keys(states)) {
if(compareMe[key] === false && states[key] === true) {
console.log("Opening Door")
} else {
console.log('No change')
}
}
compareMe = states;
await sleep(5)
}
})();
What you are doing with compareMe = states is create a new reference on the same object, so whenever you mutate states, the mutation reflects on compareMe.
You should perform a clone instead:
compareMe = { ...states };
You can use proxy object to monitor your object for changes.
original answer with more details
var targetObj = {};
var targetProxy = new Proxy(targetObj, {
set: function (target, key, value) {
// function called
console.log(`${key} set to ${value}`);
target[key] = value;
return true;
}
});
targetProxy.newProp = "test"; // console: 'newProp set to test'
However it would be easier for you to just use a library to monitor and watch variables. There are many libraries and frameworks to do this.
Library: Obseravble-Slim
Framework: Angular

Overriding an array function for a single instance

I'm trying to write a custom push function and only override it for a single instance. I'm trying to wire it up so every time I push to this array I can trigger my extra code. I don't want to override it for all Arrays or create a custom class if I don't have to.
First I had this:
let user_progress = {completed: [], inprogress: [] }
user_progress.completed.push = (item) => {
Array.prototype.push.call(user_progress.completed, item)
//do extra stuff
common.store_data(user_progress, RESOURCE_COLLECTION)
return undefined;
}
Then I tried this:
let Progress = function(){
this.completed = new Array()
this.inprogress = new Array()
}
let user_progress = new Progress()
user_progress.completed.push = (item) => {
Array.prototype.push.call(user_progress.completed, item)
common.store_data(user_progress, RESOURCE_COLLECTION)
return undefined;
}
user_progress.completed.push(item) works the first time you call it then it gets overwritten and becomes the standard Array.push. I assume it has something today with the Array.Prototype.push.call() and passing in user_progress.completed. What am i doing wrong? Both don't work and have the same issue. What is going on in the background here and is there an easy fix?

Event emitter with conditions

I've created an event emitter class. It works properly. Let me tell you how:
This is the class:
class EventEmitter{
constructor() {
this.events = {};
}
on(eventName,callback) {
if(this.events[eventName]) {
this.events[eventName].push(callback);
} else {
this.events[eventName] = [callback];
}
}
trigger(eventName, ...rest) {
if(this.events[eventName]) {
this.events[eventName].forEach(cb => {
cb.apply(null,rest);
});
}
}
}
With this class i can listen to certain events. Like so :
const ee = new EventEmitter();
ee.on('change', (aa) => {
console.log(aa);
});
Then i can trigger it with the trigger method
ee.trigger('change','Argument');
Now i want to listen to events with certain conditions.
for example :
ee.on({'change': 'barack the boss'}, (aa) => {
console.log(aa);
});
The above bit of code should only execute when trigger looks like this:
//wont run
ee.trigger('change','barack is no boss');
//will run
ee.trigger('change','barack the boss');
I wonder how to do this. I am not asking you to write my code, I would like an example or a step in the right direction.
Thank you in advance.
Whole code:
class EventEmitter{
constructor() {
this.events = {};
}
on(eventName,callback) {
if(this.events[eventName]) {
this.events[eventName].push(callback);
} else {
this.events[eventName] = [callback];
}
}
trigger(eventName, ...rest) {
if(this.events[eventName]) {
this.events[eventName].forEach(cb => {
cb.apply(null,rest);
});
}
}
}
//events has been created and is currently an empty object
const ee = new EventEmitter();
//even has been created, this event has a function which will be executed when event is triggered
ee.on({'change': 'barack the boss'}, (aa) => {
console.log(aa);
});
//wont run
ee.trigger('change','barack is no boss');
//will run
ee.trigger('change','barack the boss');
What I would do is use Object.Keys on the .on() event register. This would allow you to iterate trough the object passed (which at the same time would give you the ability to register multiple events in a single call).
With Object.Keys you can iterate trough the argument object as if it were an array. Then you can register the the value of the key as a condition when triggering the event.

TS - assign value from a callback function using return

Im getting data of class People array with each person having attendance list as Observable<any[]>.
// Class person
class Person {
id: number;
name: string;
attendance: Observable<any[]>; // An Observable array
}
// People array (I only use array for simplicity sake)
// NOTE: Every person has a list of attendance
people = Person[] = this.someService.getPeople();
Now I'm validating if some of the people may had 0 length of attendance assuming that attendance: Observable<any[]> is always an empty array [] if nothing is found, return false otherwise true to validateAttendance().
validateAttendance(): boolean {
// Loop to each person and get attendance list.
people.forEach(p => {
// Get the list using a callback function.
const func = (callback: (data) => void) => {
// Get attendance using subscribe() method
p.attendance.subscribe(list => {
callback(list);
});
}
// An attempt to get the list from a callback function
// Failed because return is undefined.
const result = func(res => {
console.log(res); // Got list of attendance of a given person.
return res;
});
if (result.length <= 0) {
alert(`${p.name} has no attendance, must be a lazy one please check.`);
return false;
}
});
return true;
}
In order to do that i attempted to create a callback function inside the validateAttendance() method and return the attendance list from it. HOWEVER the result variable is undefined!
It is possible to return a value from a callback function this way?
There are several things wrong with your code:
It is asynchronous, so the function needs to be async too (using Promise)
func() does not return a value, so the result will always be undefined.
You have alert() deep in your code. Are you going to pop up for each person with no attendance? It is better to separate logic and UI.
I have modified your code to the following:
function validateAttendance(people): Promise<boolean> {
return getPeopleWithNoAttendance(people)
.then(peopleWithNoAttendance => {
if (peopleWithNoAttendance.length > 0) {
// or loop though them
alert(`${peopleWithNoAttendance[0].name} has no attendance, must be a lazy one please check.`);
return false
}
return true
})
}
function getPeopleWithNoAttendance(people) {
return Promise.all(people.map(person => {
return new Promise(r => {
person.attendance.subscribe(r)
}).then(attendance => {
return attendance.length <= 0 ? person : undefined
})
})).then(listOfPeopleOrUndefined => {
const listOfPeople = listOfPeopeleOrUndefined.filter(p => p)
return listOfPeople
})
}
Also changed is having the people variable passed in. If this is a method in a class, feel free to change that.

Categories