Push() not working when called from inside getJSON() - javascript

I'm currently using the jQuery drag and drop formbuilder plugin. Now, I want to fetch drag and drop elements from my database and add those element to my drag and drop builder.
This is my request function:
function getElements(){
$.getJSON( getContextPath() + "/api/elements/get", function (data){
$.each(data, function(key, val) {
addElement();
});
});
}
Now, I want to add them to the formbuilder instance (I use this example and I use some pre-defined values):
function addElement(){
if (!window.fbControls) window.fbControls = [];
window.fbControls.push(function(controlClass) {
console.log("HERE");
class controlStarRating extends controlClass {
static get definition() {
return {
icon: '🌟',
i18n: {
default: 'Star Rating'
}
};
}
configure() {
this.js = '//cdnjs.cloudflare.com/ajax/libs/rateYo/2.2.0/jquery.rateyo.min.js';
this.css = '//cdnjs.cloudflare.com/ajax/libs/rateYo/2.2.0/jquery.rateyo.min.css';
}
build() {
return this.markup('span', null, {id: this.config.name});
}
onRender() {
let value = this.config.value || 3.6;
$('#'+this.config.name).rateYo({rating: value});
}
}
// register control
controlClass.register('starRating', controlStarRating);
return controlStarRating;
});
}
Unfortunately, my console.log("HERE") is not called, so it seems like it alle stops there. The weird thing is, if I use this as my request function the function is properly executed:
function getElements(){
var allElementsData = ["test"];
// $.getJSON( getContextPath() + "/api/template/get", function (data){
// });
$.each(allElementsData, function(key, val) {
addElement();
});
}
What is the problem?

In the function addElement you are pushing another function into the array window.fbControls. But that second function is only placed in the array not executed. You could for example execute it with this statement: window.fbControls[0](). Then you would see the console.log("HERE")

Related

How to use a variable returned by $.getJSON in another function

I have a javascript object with several properties and methods. I want to call the first method within the second, in order to get the default number of ingredients of a pizza and compare it with another value. However, I detect that no-value is present in the comparison of the second method.
Googling about this issue, I saw that I have to make a callback in the first method, but it didn't work for me. So, how can I be sure that the property obj.app.defaultIngredients will have a value returned by the JSON, when a 'click' event in the second method will occur? And, in that moment, I can compare the value as you also can see in the second method?
There is my (not working) code:
obj = {};
obj.app = {
defaultIngredients: '',
getDefaultIngredientsNumber: function() {
$.getJSON('/sites/all/json/pizza.json', function(data) {
var node = $('.node').attr('data-nid'),
node = 'node-' + node; // returns something like 'node-3'
$.each(data, function(key, val) {
// This returns an integer
obj.app.defaultIngredients = parseInt(data[node].general.default_ingredients);
});
}).done(function() {
return obj.app.defaultIngredients;
});
},
customAddToCart: function() {
$('#button').click(function(){
var defaultIngredients = obj.app.getDefaultIngredientsNumber();
var selectedIngredients = 0;
if defaultIngredients >= selectedIngredients) {
alert('Add some ingredients');
}
}
}
};
Some help with this will be very apreciated.
getDefaultIngredientsNumber: function(callback) {
$.getJSON('/sites/all/json/pizza.json', function(data) {
var node = $('.node').attr('data-nid'),
node = 'node-' + node; // returns something like 'node-3'
$.each(data, function(key, val) {
obj.app.defaultIngredients = parseInt(data[node].general.default_ingredients);
});
callback(obj.app.defaultIngredients)
})
},
customAddToCart: function() {
$('#button').click(function(){
obj.app.getDefaultIngredientsNumber(function(defaultIngredients) {
var selectedIngredients = 0;
if (defaultIngredients >= selectedIngredients) {
alert('Add some ingredients');
}
})
})
}
I may be missing something since seems too easy ..
});
}).done(function(data) {
return anotherfunction(data);
});
Or instead of this:
customAddToCart: function() {
$('#button').click(function(){
var defaultIngredients = obj.app.getDefaultIngredientsNumber();
var selectedIngredients = 0;
if defaultIngredients >= selectedIngredients) {
alert('Add some ingredients');
}
}
}
};
I would use this:
customAddToCart: function() {
$('#button').click(function(){
obj.app.getDefaultIngredientsNumber("alert");
}
}
};
And in the getDefaultIngredientsNumber I would check if alert is set, then perform the alert..

Wait for ajax return while in loop jquery

I've been struggling to get this to work using the $.Deferred object. Here is the stubbed setup.
g_plans = [];
$(function(){
// I have to use a custom ajax function, but it returns a promise obj
var pageLoadPromise.ajax{(
url: //call to webmethod
});
pageLoadPromise.done(matrix.buildGrid);
...
});
(function(matrix,$,undefined){
var matrix.buildGrid = function(components){
var gridData = data.d.components;
buildHeader(gridData);
buildRows(gridData);
};
function buildHeader(components){
$.each(components,function(key,component){
//does some stuff
if(this === that){
//do some other stuff
}
else{
getPlans(copmonent.COMPONENT_ID);
//does other stuff
}
});
}
}
function buildRows(components){
//does stuff, but uses data from getPlans
}
function getPlans(component){
var planPromise = ajax({
url: //call to webmethod
data:{ componentId:component}
planPromise.done(function(data){
g_plans.push({componentId:componentId,plans:data.d.plans});
});
}
})(window.matrix = window.matrix || {}, jQuery);
The problem is buildRows starts before the getPlans has time to finish it's ajax call, which is causing my issue. I have tried a few things with no success. Any help would be appreciated.
This is the easiest solution I can see:
1) Have getPlans() return the planPromise promise, which can then be handled back in the buildHeader() function.
function getPlans(component) {
var planPromise = ajax({
url: //call to webmethod
data:{ componentId:component}
});
planPromise.done(function(data) {
g_plans.push({componentId: data.componentId, plans: data.d.plans});
});
return planPromise; // return the promise!
}
2) Call buildRows() from the buildHeader() function instead of matrix.buildgrid using the promise returned from getPlans().
function buildHeader(components) {
var lastPromise;
$.each(components, function (key, component) {
lastPromise = getPlans(component.COMPONENT_ID);
});
lastPromise.done(function() {
buildRows(components);
});
}
Here's a JSFiddle illustrating the basic idea.
The second step is unnecessary, I just found it easier. The other option would be to return the lastPromise from buildHeader(), and handle it back in matrix.buildgrid.
var matrix.buildgrid = function(components) {
var gridData = components;
var lastPromise = buildHeader(gridData);
lastPromise.done(function() {
buildRows(components);
});
};
function buildHeader(components) {
var lastPromise;
$.each(components, function (key, component) {
lastPromise = getPlans(component.COMPONENT_ID);
});
return lastPromise;
}
EDIT:
To handle the case of lastPromise never getting set as a promise, you'd have to do something like this:
if (lastPromise && typeof lastPromise === 'object') {
lastPromise.done(function() {
buildRows(components);
});
} else {
buildRows(components); // or whatever needs to happen here.
}
Here's a JSFiddle including that bit in the buildHeader function.

How to get instance of the "class" from JSON string?

Given that I have a class defined such as
(function () {
function Dummy(){
var toReturn ={
myProp : "asdf",
myFunc : myFunc
}
return toReturn;
function myFunc(){};
}
})();
how does one get an instance of the same type after
var dummy = new Dummy();
JSON.stringify(dummy);
so that I have myFunc still available on the type.
JSON.parse(JSON.stringify(dummy)) returns same shape of the object by not the same type.
NOTE: I am not asking about capability of JSON, but how do people deal with this in general. Do you hand roll your mapping mechanism so that after parsing from JSON you map it onto instance of the type, or if there is such functionality in some library, such as underscore.
I created a helper function that helps me do this, but would like to hear from others how do you deal with situation like this. As I put in comments, JSON comes over the wire, for which we have a type defined. To get the values from JSON in our type, we parse json, create instance of type and then apply map function below.
function map(fromObj, toObj) {
Object.keys(fromObj)
.forEach(function (key) {
if (typeof fromObj[key] != 'function') {
if (toObj.hasOwnProperty(key)) {
if (typeof fromObj[key] !== 'object') {
toObj[key] = fromObj[key];
} else {
map(fromObj[key], toObj[key]);
}
}
}
}
});
}
Note, Not certain about requirement , if this similar to what posed at Question. If off-topic , please post comment , will withdraw.
Piece was originally composed for this Question Organizing large javascript files [on hold] . With a json response , having "x" type of contents , could map returned object to new object , copying properties utilizing $.extend() .
Result would be new object having both properties and functions of returned data. At piece below, at completion of process , $.Pages begins as function , then type gets converted to object - though it could retain both function and object properties by including || {} at definition stage.
Functions within returned json objects could be called within .then() callback ; see console at jsfiddle , object init functions.
At conclusion , $.Pages object has properties of returned json , including access to functions . Based on a jsonp - type processing flow.
Piece is "frame" of a processing approach ; could extend to include other functionality
$(function() {
var dfd = new $.Deferred();
dfd.progress(function(msg) {
console.log(msg);
});
ProductPage = {
name : "ProductPage",
addToCartBtn: "#add-to-cart",
initName : function() {return dfd.notify(this.name)},
init: function() {
this.initName();
// ProductPage.initAddToCartPopup();
// ProductPage.initSidebar();
}
};
ContactPage = {
name : "ContactPage",
validateEmail : function (e) {return dfd.notify(e)},
initName : function() {return dfd.notify(this.name)},
init: function() {
this.initName();
// ProductPage.initAddToCartPopup();
// ProductPage.initSidebar();
}
};
var mods = function() {
return {"ContactPage" : ContactPage
, "ProductPage" : ProductPage };
};
$.Pages = function() {
$.when(mods())
.done(function(pages) {
$.Pages = pages;
});
return $.Pages
};
$.when($.Pages())
.then(function() {
$.each($.Pages, function(k, v) {
v.init();
})
});
console.log($.Pages)
});
jsfiddle http://jsfiddle.net/guest271314/60kv2439/1/ (see console)
basic approach
$p = {};
var queue = [];
var mods = ["dep1.json", "service1.json"];
var mod = function(m) {
queue.push(m);
if (queue.length === mods.length) {
$.each(queue, function(k, v) {
$p = $.extend(v, $p)
})
}
};
$.each(mods, function(k, v) {
$.getScript(v, function(script, status, jqxhr) {
console.log($p)
})
})

Create a class with jQuery/javascript

In a page I create an instance of a class (MyClass), this class has 2 methods. But I'd like to do 2 things :
In (1), set the value this.message
In (2), call the information method or another method of the class
Thank,
<script type="text/javascript">
$(document).ready(function () {
var myClass = new MyClass("MyParam");
$('#Target').click(function (event) {
myClass.save("Test");
});
});
</script>
function MyClass(myParam) {
this.myParam = myParam;
this.isError = false;
this.message = "";
}
// Define the class methods.
MyClass.prototype = {
save: function (action) {
**(2)**
},
information: function (action) {
**(1)**
}
};
Update1
When I execute the code below the data value in information is show as undifined
MyClass.prototype = {
click: function (action) {
var myData;
$.post(....., $("form").serialize(),
function (data) {
myData = data;
});
this.isError = this.information(myData);
},
information: function (data) {
alert(data);
return true;
}
};
Inside the save and information functions, this should be the current MyClass object.
So, inside save, this.message should work, and inside information, this.save() should work.
UPDATE:
click: function (action) {
var myData;
$.post(....., $("form").serialize(),
function (data) {
myData = data;
});
this.isError = this.information(myData);
}
$.post is an AJAX request and is ran asynchronously. Meaning that this.isError = this.information(myData); is ran before it finishes, therefore myData is undefined. You need to call this.information from inside the callback.
Inside the callback, this will no longer be your MyClass object, so we need to save a reference to it. Like this:
click: function (action) {
var that = this;
$.post(....., $("form").serialize(),
function (data) {
that.isError = that.information(data);
});
}

knockout observable array set selected value

I am trying to populate "Select" using knockout data-bind option for a list of values and set one of the values as "selected" by default.
There are two server requests,
Get the list of values (dataRepository.GetLifelines)
Set one of the values as Selected from the list. (dataRepository.GetMockSelectedLifeline)
First requirement has been addressed. data-bind to a select is working fine with "Selected" value.
I am having issue with setting the default "Selected Value" in the list. Can someone please help me. method is this.selectValue. It is trying to set the selectedLifeline to the matching "Name".
function LifelineViewModel() {
this.lifelines = ko.observableArray([{}]);
this.selectedLifeline = ko.observable();
this.updateData = function (data) {
var boundUpdate = bind(function (value) {
this.lifelines.push(value);
}, this);
$.each(data, function (index, item) {
boundUpdate(item);
});
dataRepository.GetMockSelectedLifeline(bind(this.selectValue, this));
}
this.selectValue = function (data) {
this.selectedLifeline = ko.utils.arrayFirst(this.lifelines, function (lifeline) {
return lifeline.Name === data.Name;
});
}
}
LifelineViewModel.prototype.Init = function () {
var boundUpdateData = bind(this.updateData, this);
dataRepository.GetLifelines(boundUpdateData);
}
var bind = function (func, thisValue) {
return function () {
return func.apply(thisValue, arguments);
}
}
As selectedLifeline is an observable you are not setting its value correctly.
Could you try this. Instead of:
this.selectValue = function (data) {
this.selectedLifeline = ko.utils.arrayFirst(this.lifelines, function (lifeline) {
return lifeline.Name === data.Name;
});
}
.. something like...
this.selectValue = function (data) {
this.selectedLifeline(ko.utils.arrayFirst(this.lifelines, function (lifeline) {
return lifeline.Name === data.Name;
}));
}

Categories

Resources