Query with javascript in LightSwitch HTML client - javascript

LightSwitch tables in play:
ProductVariant
ProductVariantDetail (many to one ProductVariant)
Code:
myapp.AddEditProduct.Id_render = function (element, contentItem) {
var detailArray = new Array();
//contentItem.screen.getProductVariantDetails().then( function(result) {
// for (var i in result.data) {
// if (result.data[i].ProductVariant.Id == contentItem.value) {
// detailArray.push(result.data[i].InventoryDetail.Title);
// }
// }
// $("<div>" + detailArray.join(" / ") + "</div>").appendTo($(element));
//});
var filter = "ProductVariant eq " + contentItem.value;
myapp.activeDataWorkspace.ApplicationData.ProductVariantDetails.filter(filter).
execute().then(function (result) {
for (var i in result.results) {
detailArray.push(result.results[i].InventoryDetail.Title);
}
}).then(function() {
$("<div>" + detailArray.join(" / ") + "</div>").appendTo($(element));
});
};
The commented out code goes through EVERY ProductVariantDetail and checks if the corresponding ProductVariant matches the custom control. I discovered you can retrieve a query client-side (to save server bandwidth, see uncommented code) but my version never makes it inside filter(filter).execute. I tried "ProductVariant.Id eq" for the filter as well. Does anyone know what I might be doing wrong?

Try using this
var filter = "(ProductVariant.Id eq " + msls._toODataString(contentItem.value,":Int32")+")";

Related

Access JSON kind of data from a div?

So I have a div which displays the results from Microsoft emotion API such as:
anger: 0.28446418
contempt: 0.00341128884
disgust: 0.000332433876
fear: 0.009447911
happiness: 0.02609423
neutral: 0.6288482
sadness: 0.00180563633
surprise: 0.04559612
Here is the code for displaying the data:
.done(function(data) {
// Get face rectangle dimensions
var faceRectangle = data[0].faceRectangle;
var faceRectangleList = $('#faceRectangle');
var data1="";
// Append to DOM
for (var prop in faceRectangle) {
data1 += "<li> " + prop + ": " + faceRectangle[prop] + "</li>";
}
faceRectangleList.html(data1);
// Get emotion confidence scores
var scores = data[0].scores;
var scoresList = $('#scores');
var data2="";
// Append to DOM
for(var prop in scores) {
data2 += "<li> " + prop + ": " + scores[prop] + "</li>";
}
scoresList.html(data2);
}).fail(function(err) {
alert("Error: " + JSON.stringify(err));
});
});
}
function make_graph(){
}
Now I need to plot a line from these scores.Can you tell me how to access each separate value of these scores in another function so that I can plot them as points in my graph?
Just call make_graph from inside the done callback, passing it the data, like this.
.done(function(data) {
// ... do what you already do
make_graph(data);
}).fail(function (err) {
alert("Error: " + JSON.stringify(err));
});
function make_graph(data) {
for (d in data) {
// do stuff with data
}
}
From the given information, you can make a function like this
function drawLine(dataScores) {
for (var d in dataScores) {
// dataScores[d] will give you the score
// rest of the relevent code
}
}
and call it like this
drawLine(scores);
I think it is not good practice to write data in HTML DOM, then read it back.
But if You need this, try something like this
plotData = []
var scoresList = $('#scores')
scoresList.children('li').each(function(i) {
data = i.thml()
plotData.push(i.split(':').map(i => [i[0].trim(), parseFloat(i[1])]))
});
// here You have all data in plotData
// [['anger', 0.28446418], ...]
// Draw Your plotData here
If you want to read it back from div li, here is a jquery function to covert html to jquery data object
$(document).ready(function(){
var dataArr={};
$("#scoresli" ).each(function( index ){
data=$( this ).text().split(":");
dataArr[data[0]]=data[1]
});
alert(JSON.stringify(dataArr));
});
//{"anger":" 0.28446418\n","contempt":" 0.00341128884"}

Wait until multiple asynchronous functions complete before executing

I have a Javascript for loop which runs through an array of database records (that have been extracted already).
I want to know when all the subsequent asynchronous actions have completed but I can't seem to do it.
For each record, the code runs a number of functions which return promises and then resolve (which then triggers another function to get more information, etc). This all works ok, but I can't figure out how to gather up each "FOR" iteration and detect when all records have been processed. Basically, I want to use a "throbber" and have the throbber remain until all processing has been completed.
Code is below (I've removed some extraneous info)...
for (var i = 0; i < systemArray.length; i++) {
// ***** FOR EACH SYSTEM ***** //
var currRecord = systemArray[i];
// SECTION REMOVED //
// GET SYSTEM LINES
var thisSystem = AVMI_filterArray("8.9", currRecord);
var thisSystemName = thisSystem[1].value;
var thisSystemRID = thisSystem[0].value;
// GET CHILDREN RIDS
AVMI_getChildren(systemLinesTable, thisSystemRID, systemLinesFID).done(function(ridList, sysRID)
{
var thisDiv = "div#" + sysRID;
// GET RECORD INFO FOR EACH RID
AVMI_getMultipleRecordInfoFromArray(ridList, systemLinesTable).done(function(systemLinesArray)
{
if (systemLinesArray != "" && systemLinesArray != null) {
systemLinesArray = systemLinesArray.sort(propComparator("10"));
x = AVMI_tableCombiner("System Lines", systemLinesArray, systemLinesCLIST, "skip3Right hbars xsmallText");
$(thisDiv).append(x);
} else {
$(thisDiv).append("<p>No System Lines...</p>");
}
}
);
}
);
} // ***** FOR EACH SYSTEM ***** //
AVMI_throbberClose(); // THIS, OF COURSE, EXECUTES ALMOST IMMEDIATELY
Here is function 1
///////////////////////////////////////////////////////////////
// Get related records using master
///////////////////////////////////////////////////////////////
function AVMI_getChildren(AVMI_db, AVMI_rid, AVMI_fid, AVMI_recText) {
var AVMI_query = "{" + AVMI_fid + ". EX. " + AVMI_rid + "}";
var AVMI_ridList = [];
var dfd2 = $.Deferred();
$.get(AVMI_db, {
act: "API_DoQuery",
query: AVMI_query,
clist: "3",
includeRids: "1"
}).then(function(xml1) {
$(xml1).find('record').each(function(){
var AVMI_record = $(this);
var AVMI_childRID = AVMI_record.attr("rid");
AVMI_ridList.push(AVMI_childRID);
});
AVMI_throbberUpdate("Found " + AVMI_ridList.length + " " + AVMI_recText + "...");
dfd2.resolve(AVMI_ridList, AVMI_rid);
});
return dfd2.promise();
};
And function 2
///////////////////////////////////////////////////////////////
// Get record info for each array member
///////////////////////////////////////////////////////////////
function AVMI_getMultipleRecordInfoFromArray(ridList, AVMI_db, AVMI_recType) {
var promises = [];
var bigArray = [];
$.each(ridList, function (index,value) {
var def = new $.Deferred();
var thisArray = [];
$.get(AVMI_db, { //******* ITERATIVE AJAX CALL *******
act: 'API_GetRecordInfo',
rid: value
}).then(function(xml2) {
AVMI_throbberUpdate("Got " + AVMI_recType + " " + value + "...");
$(xml2).find('field').each(function() {
var $field = {};
$field.fid = $(this).find('fid').text();
$field.name = $(this).find('name').text();
$field.value = $(this).find('value').text();
thisArray.push($field);
});
thisArray = thisArray.sort(AVMI_ArrayComparator);
bigArray.push(thisArray);
def.resolve(bigArray);
});
promises.push(def);
});
return $.when.apply(undefined, promises).promise();
};
Any ideas of how to structure this? I've tried all sorts of things with $.Deferred but I can't quite figure it out...
You do exactly the same thing you did in AVMI_getMultipleRecordInfoFromArray: Collect the promises in an array and use $.when (or Promise.all) to wait until they are resolved.
You can simply use .map in here which also takes care of the "function in a loop" problem:
var promises = systemArray.map(function(currRecord) {
// ...
return AVMI_getChildren(...).done(...);
});
$.when.apply(undefined, promises).done(function() {
AVMI_throbberClose();
});
You should have to disable the async property of ajax. By default it is set to true. It means that your doesn't wait for your ajax response. That why it is returning you undefined value and you have to set it to false. So your code will wait your request to complete.
So all you have to do is.
$.ajax({
url: '',
type: '',
async: false,
success: function(data){
}
});

Protractor - Error: Index out of bound exception while using the same function for the second time

I have the following function which selects a category from a list of available categories. This function works fine in my first test. But the same function with a different valid category name in my second test fails with the following error.
Error: Index out of bound. Trying to access element at index: 0, but there are only 0 elements that match locator By.cssSelector(".grid-view-builder__category")
this.categoryElements = element.all(by.css('.grid-view-builder__category'));
this.selectCategory = function (categoryName) {
var filteredCategories = this.categoryElements.filter(function (category) {
return category.getText().then(function (text) {
log.info(text);
return text === categoryName;
})
})
filteredCategories.first().click().then(function () {
log.info("Select Category: " + categoryName);
}).then(null, function (err) {
log.error("Category: " + categoryName + " Not Found !!" + err);
});
}
Spec File
var columnSelect = require('pages/grid/columns/columnselector-page')()
it('Add Publisher ID Column to the Grid & Verify', function () {
var columnCountBefore = columnSelect.getColumnCount();
columnSelect.openColumnSelector();
columnSelect.selectCategory('Advanced');
columnSelect.selectColumn('Publisher ID');
columnSelect.apply();
var columnCountAfter = columnSelect.getColumnCount();
expect(columnCountAfter).toBeGreaterThan(columnCountBefore);
});
The problem might be in the way you are defining and using Page Objects. Here is a quick solution to try - if this would help, we'll discuss on why that is happening.
Make the categoryElements a function instead of being a property:
this.getCategoryElements = function () {
return element.all(by.css('.grid-view-builder__category'));
};
this.selectCategory = function (categoryName) {
var filteredCategories = this.getCategoryElements().filter(function (category) {
return category.getText().then(function (text) {
log.info(text);
return text === categoryName;
})
})
filteredCategories.first().click().then(function () {
log.info("Select Category: " + categoryName);
}).then(null, function (err) {
log.error("Category: " + categoryName + " Not Found !!" + err);
});
}
Or, this could be a "timing issue" - let's add an Explicit Wait via browser.wait() to wait for at least a single category to be present:
var EC = protractor.ExpectedConditions;
var category = element(by.css('.grid-view-builder__category'));
browser.wait(EC.presenceOf(category), 5000);
It looks like this has nothing to do with the code posted here, only that the css selector you're using is not finding any elements

Variable scope or return issue (not sure which)

Using the script below I'm attempting to create an object called temptagarray which gets populated with all the tags on a Tumblr weblog and their frequency. So it should end up looking like this:
{'performance': 10, 'installation': 5}
I know the object is being created and it looks correct (I can print it out in each loop) but I can't figure out how to use it after/outside the function i.e. at the bottom of the script where I attempt to document.write() it out. Is this a global/local variable issue, a return issue or do I need to address it in some way?
<script type="text/javascript">
var temptagarray = {};
var tags;
var tag;
function loadPosts () {
var key = "api_key=9I4rZAYQCbU1o5TSMZuyrlvXiQsNxKBicCJxNK5OKZ6G9pgdim";
var api = "https://api.tumblr.com/v2/blog/garrettlynch.tumblr.com/";
var retrieve_more = function (offset) {
$.getJSON(api + "posts?callback=?&filter=image&limit=20&offset=" + offset + "&" + key,function(data) {
//for each item (post) in the response
$.each(data.response.posts, function(i, item) {
//pull out the posts tags
tags = item['tags'];
//loop through the tags
for (i = 0; i < tags.length; i++)
{
tag = tags[i];
//if the tag already exists in the tag array
if (temptagarray[tag])
{
temptagarray[tag] = temptagarray[tag] + 1;
}
else
{
temptagarray[tag] = 1;
}
}
});
if (data.response.posts.length == 20) {
retrieve_more(offset + 20);
}
});
};
retrieve_more(0);
}
loadPosts();
document.write(JSON.stringify(temptagarray));
</script>
Thanks in advance
Garrett
Replace this:
if (data.response.posts.length == 20) {
retrieve_more(offset + 20);
}
...with this:
if (data.response.posts.length == 20) {
retrieve_more(offset + 20);
} else {
document.write(JSON.stringify(temptagarray));
}
The problem you're having is that, despite your document.write(...) command being located below the ajax call in your code, the ajax call is asynchronous and thus the callback will be invoked asynchronously as well. Basically, document.write(...) is being invoked long before you've had a chance to interact with the temptagarray variable in the ajax callback.
First things first - AJAX is Async Asynchronous.
So the code block does not wait for the previous instruction to be completed before it executes the next line.
So your document.writeline would have already been executed by the time the response comes back.
Try printing that info in the success call back after the if block and you would indeed see the response.
thanks for the replies. Below is what I have now as a workable solution as the result is going to call another function anyway. Reading a little bit more I'm wondering if I should be using a callback - is it better?
<script type="text/javascript">
//load posts from a Tumblr weblog
function loadPosts () {
//api key and weblog address
var key = "api_key=9I4rZAYQCbU1o5TSMZuyrlvXiQsNxKBicCJxNK5OKZ6G9pgdim";
var api = "https://api.tumblr.com/v2/blog/garrettlynch.tumblr.com/";
//tags object
var temptagarray = {};
//all tags and each tag
var tags;
var tag;
//looping function to keep retrieving posts until all are retrieved
var retrieve_more = function (offset) {
$.getJSON(api + "posts?callback=?&filter=image&limit=20&offset=" + offset + "&" + key,function(data) {
//for each item (post) in the response
$.each(data.response.posts, function(i, item) {
//pull out the posts tags
tags = item['tags'];
//loop through the tags
for (i = 0; i < tags.length; i++)
{
//pull out each tag
tag = tags[i];
//if the tag already exists in the tag array
if (temptagarray[tag])
{
//add 1 to its count
temptagarray[tag] = temptagarray[tag] + 1;
}
else
{
//set its count to 1
temptagarray[tag] = 1;
}
}
//to test object as it gets added to
//$("#Posts ul").append('<li>' + JSON.stringify(item, ['tags']) + '</li>')
});
//if the number of posts is more than 20
if (data.response.posts.length == 20)
{
//retrieve the next 20
retrieve_more(offset + 20);
}
else
{
//call the show result function
showresult(temptagarray);
}
});
};
//stop retrieving posts
retrieve_more(0);
}
loadPosts();
function showresult(tagarray)
{
$("#Posts ul").append('<li>' + JSON.stringify(tagarray) + '</li>');
//document.write(JSON.stringify(tagarray));
}
</script>

Using D3 to read data into associative arrays

I'm trying to loop through a set of values and read in separate files (using d3.js) into javascript associate arrays , but the argument is not being passed properly into the internal function. For example:
var reg_list = [];
var all_region_data = [];
reg_list[0]="region1";
reg_list[1]="region2";
// Function to read in data from all regions in reg_list.
function read_regional_data(region_list) {
for (i=0;i<reg_list.length;i++) {
region = region_list[i];
console.log("Read data for " + region) // THIS RETURNS REGION1, THEN
// REGION2
all_region_data[region]=new Array()
d3.csv('filepath' + region + '.csv', function(csv){
console.log('reading for ' + region) // THIS RETURNS REGION2 TWICE
csv.map(function(x) {
all_region_data[region].push(x.cause);
})
console.log("Finished Reading Data for " + region)
})
}
}
When I execute this, I iterate through both regions in the loop, but region1 is never passed into the d3.csv function. This may have something to do with the d3.csv being run asynchronously? Any thoughts on how to avoid or improve this are appreciated.
Use recursion instead of the loop to iterate over the regions --
var reg_list = [],
all_region_data = [];
reg_list[0]="region1";
reg_list[1]="region2";
function read_regional_data(i) {
var region = reg_list[i];
console.log("Read data for " + region);
all_region_data[region]=new Array();
d3.csv('filepath' + region + '.csv', function(csv){
console.log('reading for ' + region);
csv.map(function(x) {
all_region_data[region].push(x.cause);
});
console.log("Finished Reading Data for " + region);
if(i < reg_list.length) {
read_regional_data(i+1);
}
});
}
read_regional_data(0);

Categories

Resources