I am using ng2-simple-timer in my ionic3 App.
Here is code from repo:
counter: number = 0;
timerId: string;
ngOnInit() {
this.timerId = this.st.subscribe('5sec', () => this.callback());
}
callback() {
this.counter++;
}
simpletimer will create timer name and tick every 'number' of seconds.
callback will return counter value (0,1,2,3,4,5,6, etc..)
what is my problem?
I want define unique uniquecounterName: number = 0; because I have more than one timer.
what will be my results:
return uniquecounterName(0,1,2,3,4,5,6, etc..)
return otheruniquecounterName(0,1,2,3,4,5,6, etc..)
in other words callback() function must return pre defined unique variable names like as this.counter
callback(var) {
var++;
}
this one will not work because I want use var in my view.
....
It doesn't seem to be possible, if you take a look at the "GitHub: ng2-simple-timer-example", directly from the docs, you'll find how the author deals with multiple timers; I won't quote all the code, you can look at it yourself, but just paste here the way callbacks are handled:
timer0callback(): void {
this.counter0++;
}
timer1callback(): void {
this.counter1++;
}
timer2callback(): void {
this.counter2++;
}
As you can see, the whole process (new, subscribe, del, unsubscribe) is done for each timer. So the library doesn't support your use case directly.
What you could do is inline the callback function so you have access to the same variables you had when creating it:
function sub(name) {
this.timerId = this.st.subscribe(name, () => {
// still have access to the name
});
}
Of course this has to be heavily adapted to your purposes, this is as much as I could gather from your question.
Related
I'm listening to the observable that may return true or false value - the only thing that I want to do is to set throttleTime for function call when it's true and don't have it when it's false. So I did some kind of workaround for that but I don't like this solution. I have tried a different approach where I tried to do it in the actions' effect but without success..
So this is the observable:
this.store$
.pipe(
takeUntil(this.componentDestroyed$),
select(selectGlobalsFiltered([
GlobalPreferencesKeys.liveAircraftMovement])),
distinctUntilChanged()
)
.subscribe((globals) => {
if (globals && globals[GlobalPreferencesKeys.liveAircraftMovement] !== undefined) {
this.isLiveMovementEnabled = (globals[GlobalPreferencesKeys.liveAircraftMovement] === 'true');
}
if (!this.isLiveMovementEnabled) {
this.processPlaneData = throttle(this.processPlaneData, 4000);
} else {
this.processPlaneData = this.notThrottledFunction;
}
});
And as you can see I've created excat the same method that is 'pure' - notThrottledFunction and I'm assigning it when it's needed.
processPlaneData(data: Airplane[]): void {
this.store$.dispatch(addAllAirplanes({ airplanes: data }));
}
notThrottledFunction(data: Airplane[]): void {
this.store$.dispatch(addAllAirplanes({ airplanes: data }));
}
So basically this is working solution, but I'm pretty sure there is a better approach for doing such a things.
*throttle(this.processPlaneData, isLiveMovementEnabled ? 0 : 4000) doesn't work
So the second approch where I tried to do this inside of effect, I added a new argument for addAllAirplanes action - isLiveMovementEnabled: this.isLiveMovementEnabled
addAllAirplanes$ = createEffect(() =>
this.actions$.pipe(
ofType(ActionTypes.ADD_ALL_AIRPLANES),
map((data) => {
if (data.isLiveMovementEnabled) {
return addAllAirplanesSuccessWithThrottle(data);
} else {
return addAllAirplanesSuccess(data);
}
}
)
);
And then I added another effect for addAllAirplanesSuccessWithThrottle
addAllAirplanesThrottle$ = createEffect(() =>
this.actions$.pipe(
ofType(ActionTypes.ADD_ALL_AIRPLANES_THROTTLE),
throttleTime(4000),
map((data) => addAllAirplanesSuccess(data))
)
);
But it doesn't work. Can someone help me?
(It's not clear how the data arrives in your example code, but I'll assume an Observable)
throttle and throttleTime are similar to your use case, but I think it makes sense to build your own custom implementation without them. I'd suggest managing the timing yourself, using Date to determine time deltas.
You've already cached the live filtering boolean in the component state, so we can just handle all of the data stream from your position update observable and filter them out manually (which is all throttle does, but it expects you to be able to feed it an interval at subscription time, and yours needs to be dynamic).
Setup component scoped variables to contain previous timestamps, as
private prevTime: number;
private intervalLimit: number = 4000;
Supposing data$ is your input plane position data stream:
data$.pipe(filter(data => {
const now: number = Date.now();
const diff = now - this.prevTime;
if (this.isLiveMovementEnabled) {
// no throttle - pass every update, but prepare for disabling too
// record when we last allowed an update & allow the update
this.prevTime = now;
return true;
} else if (diff > intervalLimit) {
// we are throttling results, but this one gets through!
this.prevTime = now;
return true;
} else {
// we're throttling, and we're in the throttle period. eat the result!
return false;
}
}
Something like that gives you full control over the logic used whenever data comes in. You can add other operations like takeUntil and distinctUntilChanges into the pipe and trust that when you subscribe you'll be getting updated when you want them.
You can even adjust the intervalLimit to dynamically adjust the throttle period on the fly.
I have found a GitHub repository full of JavaScript algorithms and data types. The thing is, everything is written in OOP. I myself, prefer a more FP approach using small, reusable functions. What are some best practices to convert classes to smaller consumable functions?
For now, I can come up with the following working example. Is this the way to go?
OOP:
class LinkedListNode {
constructor(value, next = null) {
this.value = value;
this.next = next;
}
toString(callback) {
return callback ? callback(this.value) : `${this.value}`;
}
}
FP:
function toString(value, callback) {
return callback ? callback(value) : `${value}`;
}
function Node(value, next = null) {
return {
value,
next,
toString(callback) {
return toString(value, callback);
}
};
}
In your second example you still have a method attached to each instance, which is not ideal as soon as you want to reuse this method on a compatible interface. Also it does not play well with many FP js libraries.
To make it clear from the outside that it is not a constructor function, make it start lower case and add a prefix like create for example.
Make functions as pure as possible and do not mix code composition logic (compose, curry) with the business logic. (I talk about callback having nothing to do inside toString)
I am adding export to clearly show that at least 2 functions need to be exported.
export { nodeToString, createNode };
function nodeToString(node) {
return `${node.value}`;
}
function createNode(value, next = null) {
return {
value,
next
};
}
It would be used like this
import { nodeToString, createNode } from "./x.js";
const node = createNode(`myvalue`);
const string = nodeToString(node);
I have this load-more listener on a button that calls the functions and it works fine.
let moviesPage = 1;
let seriesPage = 1;
document.getElementById('load-more').addEventListener('click', () => {
if (document.querySelector('#movies.active-link')) {
moviesPage++;
getMovies(moviesPage);
//getMovies(genreId, moviesPage);
} else if (document.querySelector('#series.active-link')) {
seriesPage++;
getSeries(seriesPage);
}
});
Now I have another listener on a list of links that calls the following code. It takes the genreId from the event parameter to sent as an argument to the api call. Also works fine so far.
document.querySelector('.dropdown-menu').addEventListener('click',
getByGenre);
function getByGenre (e) {
const genreId = e.target.dataset.genre;
movie.movieGenre(genreId)
.then(movieGenreRes => {
ui.printMovieByGenre(movieGenreRes);
})
.catch(err => console.log(err));
};
What I want to do is to call getByGenre from the load-more listener while passing also the moviesPage argument as you can see on the commented code so it can also be passed to the api call.
What would be the best way to do that? I've looked into .call() and .bind() but I'm not sure if it's the right direction to look at or even how to implement it in this situation.
Short Answer
Kludge: Global State
The simplest, though not the most elegant, way for you to solve this problem right now is by using some global state.
Take a global selection object that holds the selected genreId. Make sure you declare the object literal before using it anywhere.
So, your code might look something like so:
var selection = { };
document.querySelector('.dropdown-menu').addEventListener('click',
getByGenre);
function getByGenre (e) {
const genreId = e.target.dataset.genre;
selection.genreId = genreId;
movie.movieGenre(...);
};
...
let moviesPage = 1;
let seriesPage = 1;
document.getElementById('load-more').addEventListener('click', () => {
if (document.querySelector('#movies.active-link')) {
...
if (selection.genreId !== undefined) {
getMovies(selection.genreId, moviesPage);
}
} else if (...)) {
...
}
});
Closure
A more elegant way for you to accomplish this is by using a closure, but for that I have to know your code structure a bit more. For now, global state like the above will work for you.
Longer Answer
Your concerns have not been separated. You are mixing up more than one concern in your objects.
For e.g. to load more movies, in your load-more listener, you call a function named getMovies. However, from within the .dropdown-menu listener, you call into a movie object's method via the getByGenre method.
Ideally, you want to keep your UI concerns (such as selecting elements by using a query selector or reading data from elements) separate from your actual business objects. So, a more extensible model would have been like below:
var movies = {
get: function(howMany) {
if (howMany === undefined) {
howMany = defaultNumberOfMoviesToGetPerCall;
}
if (movies.genreId !== undefined) {
// get only those movies of the selected genre
} else {
// get all kinds of movies
}
},
genreId : undefined,
defaultNumberOfMoviesToGetPerCall: 25
};
document.get...('.load-more').addEventListener('whatever', (e) => {
var moviesArray = movies.get();
// do UI things with the moviesArray
});
document.get...('.dropdown-menu').addEventListener('whatever', (e) => {
movies.genreId = e.target.dataset.genreId;
var moviesArray = movies.get();
// do UI things with the moviesArray
});
I'm a complete newbie to Javascript so I don't know what its capable of. Any help would be much appreciated!
As the title suggests, I'm trying to pass an argument from a function to name another function inside of it. The method below doesn't work for obvious reasons but I think it conveys what I'm trying to do. The function names need to be very specific for the project I'm working on.
function mainFunc(param1) {
function param1() {}
}
Thanks!
Edit: The software that we are going to start using to go paperless at my work uses a javascript scripting engine. In order for me to do simple things such as:
If at least one of the checkboxes in section A is checked, then you must check at least one checkbox in section B.
I would have to write a function for each and every checkbox field on the form due to the way the software works, the function name has to be specific to the name we assign to the checkbox through their GUI. I was hoping to write a function that writes another function with the specific name, and calls the said function.
function mainFunc(funcName) {
function 'funcName'() {
//do stuff;
}
'funcName'()
}
mainFunc('Checkbox1')
Maybe this will help clarify a little more on what I'm trying to do. Sorry for not being clear the first time around.
You have many options to solve your problem
one option is to return an object with the functions named using the parameters passed to mainFun look at the example below
function mainFunc(param1,param2) {
return {
[param1]:function () {
console.log(" I am function from " + param1)
},
[param2] : function () {
console.log("I am function from " + param2) ;
}
}
}
let hello = 'hello' ;
let greet = 'anything' ;
let functions = mainFunc(hello,greet);
functions['hello']();
functions['anything']();
functions[hello]();
functions[greet]();
if you have many parameters to the mainFun you can also solve it using the arguments object like the example below
function mainFun(par1) {
let myObj = {};
for(let i = 0 ; i<arguments.length;i++){
console.log(arguments[i]);
myObj[arguments[i]] = ()=> {
console.log('You call me from ' + arguments[i]);
}
}
return myObj ;
}
let functions = mainFun('a','b','c','d');
functions['a']();
functions['b']();
functions['c']();
functions['d']();
I am a relative beginner in Angular, and I am struggling to understand some source I am reading from the ng-bootstrap project. The source code can be found here.
I am very confused by the code in ngOnInit:
ngOnInit(): void {
const inputValues$ = _do.call(this._valueChanges, value => {
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
});
const results$ = letProto.call(inputValues$, this.ngbTypeahead);
const processedResults$ = _do.call(results$, () => {
if (!this.editable) {
this._onChange(undefined);
}
});
const userInput$ = switchMap.call(this._resubscribeTypeahead, () => processedResults$);
this._subscription = this._subscribeToUserInput(userInput$);
}
What is the point of calling .call(...) on these Observable functions? What kind of behaviour is this trying to achieve? Is this a normal pattern?
I've done a lot of reading/watching about Observables (no pun intended) as part of my Angular education but I have never come across anything like this. Any explanation would be appreciated
My personal opinion is that they were using this for RxJS prior 5.5 which introduced lettable operators. The same style is used internally by Angular. For example: https://github.com/angular/angular/blob/master/packages/router/src/router_preloader.ts#L91.
The reason for this is that by default they would have to patch the Observable class with rxjs/add/operators/XXX. The disadvantage of this is that some 3rd party library is modifying a global object that might unexpectedly cause problems somewhere else in your app. See https://github.com/ReactiveX/rxjs/blob/master/doc/lettable-operators.md#why.
You can see at the beginning of the file that they import each operator separately https://github.com/ng-bootstrap/ng-bootstrap/blob/master/src/typeahead/typeahead.ts#L22-L25.
So by using .call() they can use any operator and still avoid patching the Observable class.
To understand it, first you can have a look at the predefined JavaScript function method "call":
var person = {
firstName:"John",
lastName: "Doe",
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var myObject = {
firstName:"Mary",
lastName: "Doe",
}
person.fullName.call(myObject); // Will return "Mary Doe"
The reason of calling "call" is to invoke a function in object "person" and pass the context to it "myObject".
Similarly, the reason of this calling "call" below:
const inputValues$ = _do.call(this._valueChanges, value => {
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
});
is providing the context "this._valueChanges", but also provide the function to be called base on that context, that is the second parameter, the anonymous function
value => {
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
}
In the example that you're using:
this._valueChanges is the Input Event Observerable
The _do.call is for doing some side affects whenever the event input happens, then it returns a mirrored Observable of the source Observable (the event observable)
UPDATED
Example code: https://plnkr.co/edit/dJNRNI?p=preview
About the do calling:
You can call it on an Observable like this:
const source = Rx.Observable.of(1,2,3,4,5);
const example = source
.do(val => console.log(`BEFORE MAP: ${val}`))
.map(val => val + 10)
.do(val => console.log(`AFTER MAP: ${val}`));
const subscribe = example.subscribe(val => console.log(val));
In this case you don't have to pass the first parameter as the context "Observable".
But when you call it from its own place like you said, you need to pass the first parameter as the "Observable" that you want to call on. That's the different.
as #Fan Cheung mentioned, if you don't want to call it from its own place, you can do it like:
const inputValues$=this._valueChanges.do(value=>{
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
})
I suppose
const inputValues$ = _do.call(this._valueChanges, value => {
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
});
is equivalent to
const inputValues$=this._valueChanges.do(value=>{
this._userInput = value;
if (this.editable) {
this._onChange(value);
}
})
In my opinion it's not an usual pattern(I think it is the same pattern but written in different fashion) for working with observable. _do() in the code is being used as standalone function take a callback as argument and required to be binded to the scope of the source Observable
https://github.com/ReactiveX/rxjs/blob/master/src/operator/do.ts