I have the following code:
Manager.prototype.checkOrder = function() {
var finish = function(err, filled) {
if(!filled) {
log.info(this.action, 'order was not (fully) filled, cancelling and creating new order');
this.exchange.cancelOrder(this.order);
}
log.info(this.action, 'was successfull');
}
this.exchange.checkOrder(this.order, _.bind(finish, this));
}
And I don't know how to call it on other parts of the code.
I have tried this :
setTimeout(this.checkOrder, util.minToMs(1));
but it didn't work.
I want to do it without using setTimeout function.
As you are using prototypes you probably want to create an Object first. After that you can call the method like every other function.
var myManager = new Manager();
myManager.checkOrder();
Related
I have button that executes parse method
parse: function()
{
this.json.data = getDataFromAPI();
applyColor();
},
applyColor: function()
{
for (var i=0; i<this.json.data.length; i++)
{
var doc = document.getElementById(this.json.data[i].id);
doc.style.background = "red";
}
}
The problem is that applyColor cannot execute properly because this.json.data is not rendered until parse() function ends.
I'd want to achieve something like this:
this.json.data = getDataFromAPI();
exit parse() method
execute applyColor();
but without huge changes to code -> maybe some kind of "put that aside for later" like
this.json.data = getDataFromAPI();
promise(500ms) applyColor();
exit parse() method
500ms
executes applyColor()
What I've been trying?
this.$forceUpdate(); before apply
You can use the computed properties to trigger an update based on the update of other properties:
https://v2.vuejs.org/v2/guide/computed.html
But I don't fully understand why you loop through the elements of the dataset in the applyColor method and why you don't loop it in the Vue template with creating a CSS class for the style like this:
<div v-for="element, index in json.data" :key="index" class="bg-red">{{element}}</div>
you need something like this
getDataFromAPI should be promise, when data comes you send 'this' variable as a reference using self.
parse: function()
{
var self = this;
getDataFromAPI().then((data)=>{
self.json.data = data
self.applyColor();
})
},
applyColor: function()
{
for (var i=0; i<this.json.data.length; i++)
{
var doc = document.getElementById(this.json.data[i].id);
doc.style.background = "red";
}
}
Async and await seems like it will work with the least changes of code. You need to define parse with async and this.json.data = await getDataFromApi(), doing it this way , the code will execute in the exact order you have it on description, so applyColors will have this.json.data . Ref: https://javascript.info/async-await
I have a module with four functions that call one after the other. I am trying to follow the Revealing Module Pattern. One of the functions is public, the remaining are private. It goes like this:
publicMethod is called from another module
queryNames is called from publicMethod
execute(parameters, callback?, errback?) is called from queryNames
addNamesList is called as the callback? argument of execute
Several dijit/form/CheckBox's are created and the method querySegments is triggered onChange
querySegments needs to call a method of an object created in publicMethod.
The problem is in step 6, I can't reach the object created in step 1.
I have tried to use dojo hitch to define the callback? argument in step 3, but I can't get it to work. I tried putting this in its first argument, but even then I can't reach the required scope to call addNamesList.
Here is some code to demonstrate this issue.
define([
'dojo/dom',
'dijit/form/CheckBox',
'esri/layers/ArcGISDynamicMapServiceLayer',
'esri/tasks/query',
'esri/tasks/QueryTask',
'dojo/_base/lang'
],
function (
dom,
CheckBox,
ArcGISDynamicMapServiceLayer,
Query, QueryTask,
lang
) {
// ***************
// private methods
// ***************
// fetch names and call addNamesList to put the list in place
var queryNames = function (map, mapLayer) {
// new QueryTask(url, options?)
var queryTask = new QueryTask("url")
var query = new Query()
// execute(parameters, callback?, errback?)
// this callback passes an argument called featureSet
queryTask.execute(query, lang.hitch(map, "addNamesList", mapLayer), function(error) {console.log(error)})
}
// callback function of queryNames
var addNamesList = function (mapLayer, featureSet) {
console.log('addOplist')
var namesCount = featureSet.features.length
for (var i = 0; i <namesCount; i++) {
// work
var cbox = new CheckBox({
id: "cbox_" + i,
value: featureSet.features[i].attributes["someID"],
checked: false,
onChange: function (evt) {
querySegments(this.value, mapLayer)
}
})
cbox.placeAt("someDiv" + i, "first")
}
}
// triggered by the checkbox event
var querySegments = function (name, mapLayer) {
// build the query
var queryStatement = "someID = " + name
var layerDefinitions = [queryStatement]
// call a method of mapLayer
mapLayer.setLayerDefinitions(layerDefinitions)
}
// **************
// public methods
// **************
var publicMethod = function (map) {
var mapLayer = new ArcGISDynamicMapServiceLayer('restURL')
map.addLayer(mapServiceLayer)
queryNames(map, mapLayer)
return mapLayer
}
return {
publicMethod: publicMethod
}
}
)
You can see a more detailed explanation and a working example on this other (and more broad) question that I have put on Code Review.
I am new to JavaScript and I guess I still have a lot of issues with scoping, closures and callbacks.
I will deeply appreciate any input, including how to improve this question.
Edit
With this current implementation (with dojo hitch), no error is thrown. The method addNamesList is not called (nor errback, which I also don't understand why). I think this is because addNamesList is not on map's (hitch first argument) namespace. I tried to put this instead, but it makes no difference.
Before I decided to use hitch, the code looked like this:
var queryNames = function (map, mapLayer) {
...
queryTask.execute(query, addNamesList)
}
var addNamesList = function (featureSet) {
...
...
...
querySegments(this.value, mapLayer)
}
but then I couldn't reach mapLayer inside the method triggered by the check box event. It would throw Uncaught ReferenceError: mapLayer is not defined. That is why I tried to use hitch.
Javascript is asynchronous, so pretty much data coming from db, http requests or whatever is returned via callbacks. Here's what happens in your code:
public method calls queryNames
queryNames call addNamesList of map asynchronously and returns nothing
public method takes back control, meanwhile some stuff is going on with the addNamesList
mapLayer is returned untouched while some stuff is still going on in the background
So, to avoid this, you should return data from public method via callback, so you pass callback as the second parameter to the public method, then to the querySegments. Then, in the success callback of query, when you finally get the result ready, you do:
callback(mapLayer);
So, everything you should do is to pass this callback as deep as needed to the place where you have your mapLayer ready (so you've done with it everything you wanted), and then do a callback(mapLayer);.
This and this would probably explain better.
Best regards, Alexander
I'm new to meteor and I'm trying to get a hang of the whole reactivity thing.
There isn't a specifc reason why I want this function to re-run, in fact, it not re-running is actually the desired behavior for my use case. I just want to know why this is happening so I can better understand the concepts.
If I add a function as a property on a template instance, like this:
Template.services.onCreated( function() {
this.templates = [
"web_design",
"painting",
"gardening"
];
this.current_index = new ReactiveVar(0);
this.determineSlideDirection = function() {
console.log(this.current_index.get());
};
});
And then I update the reactive var in response to some event.
Template.services.events({
'click .nav-slider .slider-item': function(event, template) {
var new_selection = event.currentTarget;
template.current_index.set($(new_selection).index());
}
});
The function is not re-run upon the invocation of the set() call.
However, If I have a helper that utilizes the variable, it will be re-run.
Template.services.helpers({
currentTemplate: function() {
var self = Template.instance();
return self.templates[self.current_index.get()];
}
});
Why is this?
Reactive data sources only cause some functions to automatically re-run. These functions are:
Tracker.autorun
Template.myTemplate.helpers({})
Blaze.render and Blaze.renderWithData
In your code above you would want to use Tracker.autorun
Template.services.onCreated( function() {
this.templates = [
"web_design",
"painting",
"gardening"
];
this.current_index = new ReactiveVar(0);
Tracker.autorun(function(){
// actually, this might not work because the context of
// 'this' might be changed when inside of Tracker.
this.determineSlideDirection = function() {
console.log(this.current_index.get());
};
});
});
I have a simple requirement, I need add the same code to hundreds of other JavaScript functions, the code can be executed at the end of the function, is there a handy way of doing it, like attach an function to another function dynamically, I think yes, because JavaScript is so powerful and too powerful, any ideas?
Note, I need dynamically assign new code or function to existing functions without change existing function's code, please give a solid solution, I can do it in hacky way, but no hacky way please!
The first method that comes to mind is simply create another function:
function primaryFunction() {
// ...
utilityMethod();
}
function otherPrimaryFunction() {
// ...
utilityMethod();
}
function utilityMethod() { ... }
Now utilityMethod() gets called from the end of each other primary function.
There's also a method which requires more code refactoring but is better in the long term: classes/prototypes.
Essentially, you have one "constructor" function which takes a number of parameters for the "class" and returns an class-like object:
function constructor(someClassField, anotherField) {
this.aField = someClassField;
this.fieldTwo = anotherField;
return this;
}
Now if you call this and pass some parameters, you get a class out:
var myClass = new constructor("1", "2");
myClass.aField == "1";
myClass.fieldTwo == "2";
So: If you define your utility method as above, then you can use this: for every primary function you instantiate a new instance of the constructor, with the final code looking like this:
function constructor(primaryFunction) {
this.function = primaryFunction;
this.call = function() {
this.function();
utilityMethod();
}
this.call();
return this;
}
function utilityMethod() { ... }
var primaryMethod = new constructor(function() { ... });
The creation of primaryMethod now automatically calls the primary function followed by the utility method, before returning the object so you can re-call both if you want to.
Sorry for yet another question about callbacks. In trying to solve this problem, I've run across about a million of them. However, I'm having trouble wrapping my head around this particular scenario.
I have the code below, which obviously doesn't work as delegates apparently don't return values (I'm learning as I go, here). So, I know I need a callback at this point, but I'm not sure how to change this code to do that. Can anyone help?
function MyFunction() {
var ThisLoggedInUser = checkCurrentUser();
//do some stuff with the current user
}
function checkCurrentUser() {
var context = SP.ClientContext.get_current();
var siteColl = context.get_site();
var web = siteColl.get_rootWeb();
this._currentUser = web.get_currentUser();
context.load(this._currentUser);
context.executeQueryAsync(Function.createDelegate(this, this.CheckUserSucceeded),
Function.createDelegate(this, this.CheckUserfailed));
}
function CheckUserSucceeded() {
var ThisUser = this._currentUser.get_title();
return ThisUser;
}
function CheckUserfailed() {
alert('failed');
}
Based on your comment, you have to rething the way you want your code because you cannot use ThisUser in MyFunction().
For example you could do that:
function CheckUser() { ... }
// then call the function to find the current user
CheckUser();
// then in CheckUserSucceeded you call MyFunction()
function CheckUserSucceeded() {
MyFunction(this._currentUser.getTitle())
}
// and now you can use ThisUser in MyFunction()
function MyFunction(ThisUser) {
// do something with ThisUser
}
Your CheckUserSucceed won't return anything because it's asynchronous....
So you have to do something like that:
var ThisUser;
function CheckUserSucceeded() {
ThisUser = this._currentUser.getTitle()
// here you can call an other action and do something with ThisUser
}
You may also want to check the $SP().whoami() function from http://aymkdn.github.io/SharepointPlus/ and see the documentation.