loading a JavaScript file with vars not set at load time - javascript

the post title may not explain fully, but here is what I am hoping to do: I have my JavaScript code in a separate file, and I have it arranged like so
var PK = {
"vars" : {
"uris" : {
"app1": "http://this/server/",
"app2": "http://that/server/"
},
"something": {
"objects": [],
"obj1": { "url": PK.vars.uris.app1 },
"obj2": { "url": PK.vars.uris.app2 }
}
},
"methods" : {
"doThis" : function(a) {
$.ajax({
url: PK.vars.uris.app1,
data: data,
type: "GET",
success: function(data) { .. do something .. }
});
},
"doThat" : function(a) {
$.ajax({
url: PK.vars.uris.app2,
data: data,
type: "GET",
success: function(data) { .. do something else .. }
});
},
"init" : function(position) {
if (position) { PK.methods.doThis();
}
else {
PK.methods.doThat();
}
}
}
};
and then, in my html, I have the following
$(document).ready(function() {
PK.vars.uris.app1 = "[% app1 %]";
PK.vars.uris.app2 = "[% app2 %]";
PK.methods.init();
});
where the values of app1 and app2 are sent from the server based on a config file. Except, it doesn't work as expected, because, when the separate JavaScript loads, PK.vars.uris is not defined at that time. Of course, everything works beautifully if I have PK.vars.uris{} hardcoded.
How can I delay the evaluation of var PK until after the document has loaded and PK.vars.uris is available to be used in the JavaScript code?

Is the problem that you need to pass values into an initialiser?
How's this approach:
In your external file:
function PK_Constructor(app1Uri, app2Uri) {
this.vars = { "uris" : {
"app1" : app1Uri,
"app2" : app2Uri
},
"something": {
"objects": [],
"obj1": { "url": app1Uri },
"obj2": { "url": app1Uri }
},
};
this.doThis = function(a) {
$.ajax({
url: this.vars.uris.app1,
data: data,
type: "GET",
success: function(data) { .. do something .. }
});
// etc
}
And in you HTML:
// Ensuring PK has global scope
var PK = undefined;
$(document).ready(function() {
PK = new PK_Constructor("[% app1 %]", "[% app2 %]");
});

Related

Trying to create a URL in my JSON, but not sure if this is the right way

how I would like to have it in my JSON (this is an example):
"audio": "https://test.diglin.eu/media/audio/nl_NL/bal.mp3"
how my code looks like:
exObject['exerciseGetWordInput'] =
$(this).find('input.exerciseGetWordInput').val();
var audioId = MEDIAARRAY.audio.lowercase.indexOf(exObject['exerciseGetWordInput'].toLowerCase() + '.mp3');
var audio_link = '';
if (audioId > -1) {
exObject['audio'] = 'https://test.diglin.eu' + MEDIAARRAY.audio.path + MEDIAARRAY.audio.files[audioId];
}
the code above should be implemented into my function, but I don't know how to pass this on to my ajax call exactly.
The function where it all happens:
function setMainObjectArray() {
var exercises = [];
var eBlocks = $('.eBlock');
eBlocks.each(function(i, eBlock) {
var exObject = {
word: $(eBlock).find('input.ExerciseGetWordInput').val(),
syllables: [],
};
exObject['exerciseGetWordInput'] = $(this).find('input.exerciseGetWordInput').val();
var audioId = MEDIAARRAY.audio.lowercase.indexOf(exObject['exerciseGetWordInput'].toLowerCase() + '.mp3');
var audio_link = '';
if (audioId > -1) {
exObject['audio'] = 'https://test.diglin.eu' + MEDIAARRAY.audio.path + MEDIAARRAY.audio.files[audioId];
}
$(eBlock).find('input.syllable').each(function(j, syll) {
exObject.syllables.push($(syll).val());
});
exercises.push(exObject);
});
return exercises;
}
my ajax call:
function saveExerciseAjaxCall() {
console.log(setMainObjectArray());
$.ajax({
url: 'saveJson.php',
type: 'POST',
data: {
id: getUrlParameter('id'),
getExerciseTitle: $('#getExerciseTitle').val(),
language: $('#languageSelector').val(),
application: 'lettergrepen',
'main_object': {
title: $('#getExerciseTitle').val(),
language: $('#languageSelector').val(),
exercises: setMainObjectArray()
},
dataType: 'json'
}
}).done(function(response) {
}).fail(function(jqXHR, textStatus, errorThrown){
console.log(jqXHR);
console.log(errorThrown);
console.log(textStatus);
});
}
ur most likely wondering why I just don't give it a try and see what happens (or you could use the argument: Why don't you test it with a JSON validator? This because I have done such thing once before and my application crashed all the way. yet the JSON validator gave me "valid JSON").
EDIT: So you can see the complete JSON, it should look something like this:
{
"exercisetitle": "dedew",
"application": "",
"language": "nl_NL",
"id": "new",
"main_object": {
"title": "dedew",
"exercises": [
{
"word": "aap",
"audio": "https://test.diglin.eu/media/audio/nl_NL/aap.mp3"
}
]
}
}

How can i fix my module pattern to work

I have a module in a different file which should essentially carry out my ajax requests for me (this is in ajaxCall.js), I am trying to add this module to the global window object so that i can use it in another file called (basket-page.js), but I get an error stating
Uncaught TypeError: Cannot read property 'process' of undefined(…)
AjaxCall.js
"user strict";
window.ajaxCall = window.ajaxCall || {}
var ajaxCall = (function () {
var api = {
process: function (destinationUrl, dataToPost, callbackFunction) {
$.ajax({
url: destinationUrl,
data: dataToPost,
method: "POST",
dataType: "JSON",
success: function (data) {
if (element.length > 0) {
callbackFunction(data, element);
}
},
error: function (req, status, errorObj) {
console.log(status);
}
});
}
}
window.ajaxCall = api;
return api;
})();
basket-page.js
"use strict";
basket = basket || {};
var basket = (function (ajax) {
var api = {
init: function () {
$("#tblBasket").dataTable({
bFilter: false,
pageLength: 10,
paging: true,
autoWidth: true,
columns:
[
{ "orderDataType": "dom-text", type: "string" },
{ "orderDataType": "dom-text-numeric" },
null
],
fixedColumns: true
});
},
removeBasketProductRow: function (data, element) {
if (data === true) {
element.remove();
}
}
};
$("#btnRemoveBasketProduct").click(function() {
var product = $(this).closest("tr");
var productId = product.attr("id");
window.ajaxCall.process("/Products/RemoveBasketProduct", productId, api.removeBasketProductRow);
});
return api;
})(window);
$(document).ready(function () {
basket.init();
});
Remove all the function wrapping. It's unnecessary.
"user strict";
window.ajaxCall = {
process: function (destinationUrl, dataToPost, callbackFunction) {
$.ajax({
url: destinationUrl,
data: dataToPost,
method: "POST",
dataType: "JSON",
success: function (data) {
if (element.length > 0) {
callbackFunction(data, element);
}
},
error: function (req, status, errorObj) {
console.log(status);
}
});
}
}
The issue was making sure i had my other script file loaded already, since this is what adds object to the global window object.

Data not populating the table created using jsgrid

I'm using jsgrid to create an editable table. i used the code from this demo. The only difference is im using mvc instead of web api.
Looking at the network, the controller returns the needed json data and jsgrid also shows the pagination stuff on the bottom of the table. However, the table is not being populated
Here's the html and javascript code
<div id="jsGrid"></div>
#section scripts {
<script src="http://js-grid.com/js/jsgrid.min.js"></script>
<script>
$("#jsGrid").jsGrid({
height: "50%",
width: "100%",
filtering: true,
inserting: true,
editing: true,
sorting: true,
paging: true,
autoload: true,
pageSize: 10,
pageButtonCount: 5,
deleteConfirm: "Do you really want to delete client?",
controller: {
loadData: function (filter) {
return $.ajax({
type: "GET",
url: "get",
data: filter,
dataType: "json"
});
},
insertItem: function (item) {
},
updateItem: function (item) {
},
deleteItem: function (item) {
}
},
fields: [
{ name: "SKU", type: "text", width: 50 },
{ name: "PartNumber", type: "text", width: 100 },
{ name: "ProductLineName", type: "text", width: 50 },
{ name: "ProductLineId", type: "text", width: 50 },
{ name: "Deleted", type: "checkbox", sorting: false },
{ type: "control" }
]
});
</script>
Here's the relevant method in the controller
public async Task<ActionResult> Get()
{
var query = db.Products
.Select(p => new ProductDto()
{
PartNumber = p.PartNumber,
SKU = p.SKU,
ProductLineName = p.ProductLines.ProductLineName,
ProductLineId = p.ProductLineId,
Deleted = p.Deleted
});
var products = await query.ToListAsync();
return Json(products, JsonRequestBehavior.AllowGet);
}
Anyone know what i can do to display/bind the returned data to the table?
Change your loadData call because its not specifying what to do when ajax call is done.
Try to rewrite it like below :
controller: {
loadData: function() {
var d = $.Deferred();
$.ajax({
url: "get",
dataType: "json",
data: filter
}).done(function(response) {
d.resolve(response.value);
});
return d.promise();
}
},
This is the client side javascript that I used which finally put some data in the grid: (just the controller part)
controller: {
loadData: function (filter) {
console.log("1. loadData");
return $.ajax({
type: "GET",
url: "/Timesheet/GetTimesheet/",
dataType: "json",
data: filter
console.log("3. loadData complete");
}
None of the posted explicit promise code functioned at all. Apparently $.ajax returns a promise.
and this was my MVC controller code that I called with ajax (C#):
public async Task<ActionResult> GetTimesheet()
{
int id = Convert.ToInt32(Session["UID"]);
var tl = (
from ts in db.Tasks
orderby ts.Task_Date descending
where ts.Emp_ID == id
select new
{
ID = ts.Task_ID,
Date = ts.Task_Date,
Client = ts.Customer_ID,
Hours = ts.Total_Hours
}
).Take(4);
var jsonData = await tl.ToListAsync();
return Json(jsonData, JsonRequestBehavior.AllowGet);
}
There are no actual examples of required Json for jsGrid. anywhere but this worked for me - note no headers or anything.

JStree Async Search

Whe are busy building a web based app. And we inherited the code where the previous developers used jstree so now the whole site consist out of a tree that uses jstree.
Everything worked even the search on the tree, but then we came across a problem where certain tabs loaded too long because of the tree which was too big.
So we went and made the the tree async / lazy loading which works perfectly but know the problem is that the search doesn't work that well.
Because we made a api for the search which works but it doesn't do the call back after new tree has been loaded.
Can someone help because I've been struggling for 3 days now and its giving me a head ache.
// Tree Search
searchAjaxFunction: function () {
var TreeCustomApiRequest = {
nTreeCustomDesc: document.getElementById("tree_search").value,
nUserId: document.getElementById("TrendUserID").value,
nAccessLevel: document.getElementById("hfTrendAccessLevel").value
}
$.ajax({
type: "POST",
data: JSON.stringify(TreeCustomApiRequest),
url: 'api/TreeCustomSearch.aspx',
success: function (jsonData)
{
Tree.dataJson = jsonData;
// Clear the tree.
//Tree.dataJson = jsonData;
if ($("#tree").jstree()) {
$('#tree').jstree(true).settings.core.data = jsonData;
$('#tree').jstree(true).deselect_node(this);
$('#tree').jstree(true).toggle_node(this);
$('#tree').jstree(true).refresh();
}
},
contentType: "application/json"
});
},
onClickFunctionNode: function(node) {
Tree.treeDivIdSelector.jstree(true).toggle_node(node);
},
pluginsArray: ["search", "checkbox", "types", "json_data","html_data"],
treeMenuContextItems: {},
Init: function(initData) {
Tree.dataJson = initData.dataJson;
Tree.treeDivIdSelector = initData.chartDivId;
Tree.searchDivIdSelector = initData.searchDivId;
var apiUriTree = 'api/TreeCustomChildren.aspx';
Tree.treeDivIdSelector.jstree({
"checkbox": {
"keep_selected_style": true,
"three_state": false
},
"plugins": Tree.pluginsArray,
'core': {
'data': function (node, cb) {
// Fetch tree custom parent nodes
if (node.id === "#") {
cb(Tree.dataJson);
}
else {
var _cb = cb;
//Fetch tree custom Child nodes
var TreeCustomApiRequest = {
nUserId: document.getElementById("TrendUserID").value,
nAccessLevel: document.getElementById("hfTrendAccessLevel").value,
nTreeCustomParentId: node.id
}
function recieveData(data) {
cb(data);
}
$.ajax({
type: "POST",
data: JSON.stringify(TreeCustomApiRequest),
url: apiUriTree,
success: recieveData,
contentType: "application/json"
});
}
},
"themes": {
"icons": false
}
},
"contextmenu": {
items: Tree.pluginsArray.indexOf("contextmenu") > -1 ? Tree.treeMenuContextItems : null
}
});
var tree = Tree.treeDivIdSelector.jstree();
function getNode(sNodeID) {
return tree.get_node(sNodeID);
}
Tree.treeDivIdSelector.on('click', '.jstree-anchor', function(e) {
Tree.onClickFunctionNode(this);
}
);
//Tree.searchDivIdSelector.keyup(Tree.searchFunction);
},
The next code is in the client side......
<script type="text/javascript">
$(document).ready(function () {
var dataJson = <%=sTreeViewJson%>
Tree.Init({ dataJson: dataJson, chartDivId: $("#tree") });
$("#btnSearch").click(function () {
// Do the Ajax search
Tree.searchAjaxFunction();
//var value = document.getElementById("tree_search").value;
//Tree.searchFunction();
})
});
</script>
Thank you Nikolay, it was a stupid mistake from me so what I added was just this to my code:
success: function (jsonData, callback )
{
//Goes back to the Callback with the new search data
Tree.Init({ dataJson: jsonData, chartDivId: $("#tree"), searchDivId: $("#tree_search") });
$('#tree').jstree(true).refresh();
}
So I removed the
$('#tree').jstree(true).settings.core.data = jsonData;
$('#tree').jstree(true).deselect_node(this);
$('#tree').jstree(true).toggle_node(this);
Know it gets my data and refreshes the table with the init function while it has my new data.
Hope this also may help someone = ).

Ajax Request Loop and Wait Until Complete

Is there a more efficient way to write the following? I need to loop through objList and pass the UnqKey to wfrmPrint. On success of that I then have to loop though the Pages. I am looping through the pages and unqkeys by passing a integer and checking to see if it is less than the length. I tried to use .when.apply taken from http://www.tentonaxe.com/index.cfm/2011/9/22/Using-jQuerywhen-with-a-dynamic-number-of-objects, but it was loading the unqkeys and then the pages.
//sample objList
[
{
"UnqKey": 1,
"Pages": [
"wfrmSet1Page1.aspx",
"wfrmSet1Page2.aspx"
]
},
{
"UnqKey": 2,
"Pages": [
"wfrmSet2Page1.aspx",
"wfrmSet2Page2.aspx",
"wfrmSet3Page2.aspx",
"wfrmSet4Page2.aspx"
]
}
]
function Loop(iListIndex) {
var obj = objList[iListIndex];
if (iListIndex < objList.length) {
jQuery.ajax({
type: "GET",
url: 'wfrmPRINT.aspx?action=LoadSession&UnqKey=' + obj.UnqKey, //load session that is used in wfrmSet1Pages.. or wfrmSet2Pages..
success: function () {
AddPages(obj, iListIndex, 0);
}
})
} else {
alert('Done');
}
}
function AddPages(obj, iListIndex, iPageIndex) {
if (iPageIndex < obj.Pages.length) {
jQuery.ajax({
type: "GET",
url: obj.Pages[iPageIndex] + '?Print=1', //load html
async: true,
success: function (html) {
iPageIndex++
AddPages(obj, iListIndex, iPageIndex);
},
error: function () {
alert('Failed!');
iPageIndex++
AddPages(obj, iListIndex, iPageIndex);
}
});
} else {
iListIndex++
Loop(iListIndex);
}
}
You might be able to do something like this,
function getData(arr,arrindex) {
$.ajax({
type: "GET",
url: 'wfrmPRINT.aspx?action=LoadSession&UnqKey=' + arr[arrindex].UnqKey
}).then(function(data){
var deferredObj = $.Deferred(), defArr = $.map(arr[arrindex].Pages,function(page){
return $.ajax({type: "GET", url: page + '?Print=1'});
});
$.when.apply(null,defArr).done(deferredObj.resolveWith).fail(deferredObj.resolveWith);
return deferredObj.promise();
}).done(function(){
arrindex++;
if (arr[arrindex]) {
getData(arr,arrindex);
}
else {
alert("done!");
}
}).fail(function(){
alert("FAIL!");
});
}
getData(objList,0);
It gets each wfrm sequentially, and when each one finishes, requests all of the pages for that one at once. Somewhat of a combination between your loop and a deferred $.when
Edit: fixed $.map argument order

Categories

Resources