Google Docs and xml reading - javascript

i've working code(below) to read xml in google docs. It works greate if xml looks like this(part i'm interested in):
<row orderID="4452813795" charID="96255569" stationID="60011752" volEntered="1" volRemaining="1" minVolume="1" orderState="0" typeID="11134" range="32767" accountKey="1002" duration="90" escrow="0.00" price="20000.00" bid="0" issued="2016-02-28 02:05:29"/>
What i want is volRemaining value and my code returns 1. But if xml looks like this:
<row orderID="4452813795" charID="96255569" stationID="60011752" volEntered="1" volRemaining="1" minVolume="1" orderState="0" typeID="11134" range="32767" accountKey="1002" duration="90" escrow="0.00" price="20000.00" bid="0" issued="2016-02-28 02:05:29"/>
<row orderID="4452814032" charID="96255569" stationID="60011752" volEntered="1" volRemaining="1" minVolume="1" orderState="0" typeID="11134" range="32767" accountKey="1002" duration="90" escrow="0.00" price="20000.00" bid="0" issued="2016-02-28 02:05:47"/>
Code still returns 1. What i need is to add these values from both rows so that code returns 2 in this case(there may be more rows like these and code need to check if orderState="0").
This is my code:
function getLevelByTypeFromRowset(rowset, id)
{
var rows = rowset.getChildren("row");
var level=null;
var level2=0;
for (var i=0;level==null && i<rows.length;i++)
{
var row=rows[i];
var typeIdAttr=row.getAttribute("typeID");
if (typeIdAttr && typeIdAttr.getValue()==id && row.getAttribute("orderState").getValue()==0)
{
level2=level2 + row.getAttribute("volRemaining").getValue();
if (i = rows.length){
level=level2;
}
}
}
return level;
}
function TradeVolume(id) {
//id=3389;
var idd="orders";
var url = "http://some.url.com";
var document = readXml(url);
var level = null;
var rowsets = document.getRootElement().getChild("result").getChildren("rowset");
for (var i=0;level==null && i<rowsets.length;i++)
{
var rowset=rowsets[i];
var typeIdAttr=rowset.getAttribute("name");
if (typeIdAttr && typeIdAttr.getValue()==idd)
{
level=getLevelByTypeFromRowset(rowset, id);
}
}
if (level==null){
level = 0
}
return parseFloat(level);
}
I've been trying to do it 3 hours and can't came up with any idea...
Edit:
Working code:
function getLevelByTypeFromRowset(rowset, id)
{
var rows = rowset.getChildren("row");
var level=0;
for (var i=0;i<rows.length;i++)
{
var row=rows[i];
var typeIdAttr=row.getAttribute("typeID");
if (typeIdAttr && typeIdAttr.getValue()==id && row.getAttribute("orderState").getValue()==0)
{
level=parseInt(level) + parseInt(row.getAttribute("volRemaining").getValue());
}
}
return level;
}

One problem is if (i = rows.length). You are making an assignment there, where you apparently meant to test for equality. The assignment causes the loop condition to be false, so the loop terminates early.
So you could change the if condition to if (i == rows.length). However, that test will never be true, since the loop condition includes && i<rows.length. Maybe you meant to say if (i == rows.length - 1), so that the body of the if would be executed on the last pass through the loop? But it would only happen if the last row satisfies
(typeIdAttr && typeIdAttr.getValue()==id && row.getAttribute("orderState").getValue()==0)
which I don't think is what you want.
Really what I expect you meant was to move the
if (i == rows.length - 1) {
level = level2;
}
outside of the block of the preceding if. But a simpler way of doing the same thing would be to remove this if block completely, and change
return level;
to
return level2;

Related

Weird issue with Vue / Javascript variables

I honestly don't even know how to search for this question (what search param to write) but either way its bit weird issue and I am desperate for help.
So I am trying to do something simple, event sends "form-change" and when it does, we set new value in "this.data" object. Fairly simple. I don't expect this.data to be reactive I just want to update it.
// Find our data object which we want to update/change
if (form.field.includes('.')) {
let find = form.field.split('.'), level = this.data;
for (let index = 0; index < find.length; index++) {
if (level[find[index]] !== undefined) {
level = level[find[index]];
} else {
level = undefined;
}
}
if (level !== undefined)
level = setFieldData();
}
This is fairly simple, we have name of field "inspect.book" and when update comes (Event) we just use dots to split into multi tree and update "this.data.inspect.book" to new value. But it does not work. Value does not change.
But the value from actual this.data.inspect.book comes out just fine using:
console.log(level);
However, if I do this:
this.data[ form.field.split( '.' )[ 0 ] ][ form.field.split( '.' )[ 1 ] ] = setFieldData();
It works fine. So "reference" to variable does not work... how is this possible? Looks like a bug in javascript or is it something with vue/reactivity?
Does anyone have better idea how to get this to work?
So you are trying to update form data using to notation ?
i would do something like that :
_update(fieldName, value) {
// We split segments using dot notation (.)
let segments = fieldName.split(".");
// We get the last one
let lastSegment = segments.pop();
// We start with this.data as root
let current = this.data
if(current) {
// We update current by going down each segment
segments.forEach((segment) => {
current = current[segment];
});
// We update the last segment once we are down the correct depth
current[lastSegment] = val;
}
},
if i take your example :
if (form.field.includes('.')) {
let find = form.field.split('.'), level = this.data;
for (let index = 0; index < find.length - 1; index++) {
if (level[find[index]] !== undefined) {
level = level[find[index]];
} else {
level = undefined;
}
}
if (level !== undefined)
level[find.pop()] = setFieldData();
}
i replaced find.length by find.length - 1
and replaced level = setFieldData() by level[find.pop()] = setFieldData()
you should update the property of the object, without actually overriding the value,
because if you override the value, the original value will not get updated.

.length on array crashing when length is 1 (maybe issue with split)

I'm having trouble with this code. I've tried to troubleshoot it many times and seem to have isolated the issue, but can't figure out the cause.
If the variable called string is set to something in the form of "text v. text," the code runs fine and the first if-statement triggers the sentence. If the string contains text but no "v." i.e. nothing that meets the search separator value, the function fails and does not execute the second if-statement.
Link to Fiddle: http://jsfiddle.net/qsq4we99/
Snippet of code, there also would need to be a html div with ID "outputtext."
function brokenCode()
{
//Setting Relevant Variables
var string = "red";
var array = string.split("v.");
var number = array.length;
// Checking location of things
var findText1 = array[0].search("search text");
var findText2 = array[1].search("search text");
//Running Conditional Stuff
if(number > 1)
{
document.getElementById('outputtext').innerHTML = "2+ listed";
}
else if(number < 2)
{
document.getElementById('outputtext').innerHTML = "1 listed";
}
}
brokenCode();
In this simplified example there is no clear explanation why the search operations need to occur (they are there because in the real code they are needed... but something about them seems to be causing the problem (even in this simple example). If the two searches are removed, the code runs smoothly.
You can't start setting variables from the array without checking for length. Before setting findText1 & findText2, check to make sure the length of the array is greater than zero.
function brokenCode() {
//Setting Relevant Variables
var string = "red";
var array = string.split("v.");
var number = array.length;
if (number > 0) {
// Checking location of things
var findText1 = array[0].search("search text");
var findText2 = array[1].search("search text");
//Running Conditional Stuff
if(number > 1)
{
document.getElementById('outputtext').innerHTML = "2+ listed";
}
else if(number < 2)
{
document.getElementById('outputtext').innerHTML = "1 listed";
}
}
}
brokenCode();

AngularJS initially fill array with true, one for each in model

I want to have an array with values, one 'true' for each object in my model.
As you can see in my JSFiddle - Hardcoded working, I have currently hard coded the values, and then it works, i.e. the "level 2" tables being collapsed from start.
$scope.dayDataCollapse = [true, true, true, true, true, true];
$scope.dayDataCollapseFn = function () {
for (var i = 0; $scope.storeDataModel.storedata.length - 1; i += 1) {
$scope.dayDataCollapse.append('true');
}
};
But when I replace the hardcoded with an empty array and a function (shown above) to populate it for me, meaning appending 'true' for each store in the storeDataModel, it fails. All level 2 tables are expanded from start, but can collapse them by clicking two times (one for adding value to array and one for collapsing).
Have also tried with a "real" function...:
function dayDataCollapseFn() {
for (var i = 0; $scope.storeDataModel.storedata.length - 1; i += 1) {
$scope.dayDataCollapse.append('true');
}
};
...but I can't get the $scope.dayDataCollapse to populate initally.
How can I solve this?
Your for loop is incorrect. The middle expression is evaluated for true/false, but you've just coded it to be a constant value (well, constant for any invocation of the function anyway). Try this:
function dayDataCollapseFn() {
for (var i = 0; i < $scope.storeDataModel.storedata.length; i += 1) {
$scope.dayDataCollapse.push(true);
}
};
Your function would have done nothing at all if the model had one element, and locked up the browser with a "slow script" warning if the model had zero or more than one elements.
Also note that you should use true, the boolean constant, and not the string 'true'.
edit — also note that it's .push(), not .append()
#Pointy got me in right direction...thanks! =)
...and then I solved the last thing.
I forgot that I had used a negation, i.e. data-ng-show="!dayDataCollapse[$index]" since I was using collapse="dayDataCollapse[$index]" first. Then I removed the collapse since it didn't work well together.
Anyhow...since I removed the bang (!) I could also use false instead of true and then of course switch the booleans in the $scope.selectTableRow() function as well.
The last thing was that I had if-else, where the if statement checked if dayDataCollapse was undefined and then an else for the logic. Of course the logic did not trigger first time as it was undefined.
Functions that made it work...:
$scope.dayDataCollapseFn = function () {
$scope.dayDataCollapse = [];
for (var i = 0; i < $scope.storeDataModel.storedata.length; i += 1) {
$scope.dayDataCollapse.push(false);
}
};
$scope.selectTableRow = function (index, storeId) {
if ($scope.dayDataCollapse === undefined) {
$scope.dayDataCollapseFn();
}
if ($scope.tableRowExpanded === false && $scope.tableRowIndexCurrExpanded === "" && $scope.storeIdExpanded === "") {
$scope.tableRowIndexPrevExpanded = "";
$scope.tableRowExpanded = true;
$scope.tableRowIndexCurrExpanded = index;
$scope.storeIdExpanded = storeId;
$scope.dayDataCollapse[index] = true;
} else if ($scope.tableRowExpanded === true) {
if ($scope.tableRowIndexCurrExpanded === index && $scope.storeIdExpanded === storeId) {
$scope.tableRowExpanded = false;
$scope.tableRowIndexCurrExpanded = "";
$scope.storeIdExpanded = "";
$scope.dayDataCollapse[index] = false;
} else {
$scope.tableRowIndexPrevExpanded = $scope.tableRowIndexCurrExpanded;
$scope.tableRowIndexCurrExpanded = index;
$scope.storeIdExpanded = storeId;
$scope.dayDataCollapse[$scope.tableRowIndexPrevExpanded] = false;
$scope.dayDataCollapse[$scope.tableRowIndexCurrExpanded] = true;
}
}
Updated JSFiddle

For Loop/Each Loop variable storage and comparison (jQuery or Javascript

I have an each loop with jquery (I wouldn't mind using a for loop if the code works better) and it's cycling through all divs with the class="searchMe". I would like to store the current div in a variable that I can use in the next iteration of the loop to compare a value with the new current div. Some code is removed (all working) to simplify things, but here's my code:
$('.searchMe').each(function(){
var id = $(this);
sortUp += 1,
sortDown -= 1;
if (test) {
id.attr("name", ""+sortUp+"");
}
else {
id.attr("name", ""+sortDown+"");
}
if ( id.attr("name") > lastId.attr("name") ) {
id.insertBefore(lastId);
}
lastId = id; //this doesn't work, but illustrates what I'm trying to do
});
Everything is working properly except the last 3 lines.
is this possible with an each/for loop?
I don't know why sort up is needed when you are comparing backwards alone. you can replace the last three lines with...
if ( parseInt(id.attr("name")) > parseInt(id.prev().attr("name")) ) {
id.insertBefore(id.prev()).remove();
}
you can use index in $.each()
like
$('.searchMe').each(function(index){
var id = $(this);
sortUp += 1,
sortDown -= 1;
if (test) {// don't know what is test, let it is predefined
id.attr("name", sortUp);// no need to add ""
}
else {
id.attr("name", sortDown);
}
if ($('.searchMe').eq(index-1).length && id.attr("name") > $('.searchMe').eq(index-1).attr("name") ) {
id.insertBefore($('.searchMe').eq(index-1));
}
});
Or Alternatively you can define lastid like
var lastId='';// let it be global
$('.searchMe').each(function(index){
var id = $(this);
sortUp += 1,
sortDown -= 1;
if (test) {// don't know what is test, let it is predefined
id.attr("name", sortUp);// no need to add ""
}
else {
id.attr("name", sortDown);
}
if (id.attr("name") > lastId.attr("name") ) {
id.insertBefore(lastId);
}
lastId=id;// assign here the current id
});
Read eq() and $.each()

javascript not removing undefined objects from array

I've got an in page text search using JS, which is here:
$.fn.eoTextSearch = function(pat) {
var out = []
var textNodes = function(n) {
if (!window['Node']) {
window.Node = new Object();
Node.ELEMENT_NODE = 1;
Node.ATTRIBUTE_NODE = 2;
Node.TEXT_NODE = 3;
Node.CDATA_SECTION_NODE = 4;
Node.ENTITY_REFERENCE_NODE = 5;
Node.ENTITY_NODE = 6;
Node.PROCESSING_INSTRUCTION_NODE = 7;
Node.COMMENT_NODE = 8;
Node.DOCUMENT_NODE = 9;
Node.DOCUMENT_TYPE_NODE = 10;
Node.DOCUMENT_FRAGMENT_NODE = 11;
Node.NOTATION_NODE = 12;
}
if (n.nodeType == Node.TEXT_NODE) {
var t = typeof pat == 'string' ?
n.nodeValue.indexOf(pat) != -1 :
pat.test(n.nodeValue);
if (t) {
out.push(n.parentNode)
}
}
else {
$.each(n.childNodes, function(a, b) {
textNodes(b)
})
}
}
this.each(function() {
textNodes(this)
})
return out
};
And I've got the ability to hide columns and rows in a table. When I submit a search and get the highlighted results, there would be in this case, the array length of the text nodes found would be 6, but there would only be 3 highlighted on the page. When you output the array to the console you get this:
So you get the 3 tags which I was expecting, but you see that the array is actually consisting of a [span,undefined,span,undefined,undefined,span]. Thus giving me the length of 6.
<span>
<span>
<span>
[span, undefined, span, undefined, undefined, span]
I don't know why it's not stripping out all of the undefined text nodes when I do the check for them. Here's what I've got for the function.
performTextSearch = function(currentObj){
if($.trim(currentObj.val()).length > 0){
var n = $("body").eoTextSearch($.trim(currentObj.val())),
recordTitle = "matches",
arrayRecheck = new Array(),
genericElemArray = new Array()
if(n.length == 1){
recordTitle = "match"
}
//check to see if we need to do a recount on the array length.
//if it's more than 0, then they're doing a compare and we need to strip out all of the text nodes that don't have a visible parent.
if($(".rows:checked").length > 0){
$.each(n,function(i,currElem){
if($(currElem).length != 0 && typeof currElem != 'undefined'){
if($(currElem).closest("tr").is(":visible") || $(currElem).is(":visible")){
//remove the element from the array
console.log(currElem)
arrayRecheck[i] = currElem
}
}
})
}
if(arrayRecheck.length > 0){
genericElemArray.push(arrayRecheck)
console.log(arrayRecheck)
}
else{
genericElemArray.push(n)
}
genericElemArray = genericElemArray[0]
$("#recordCount").text(genericElemArray.length + " " +recordTitle)
$(".searchResults").show()
for(var i = 0; i < genericElemArray.length; ++i){
void($(genericElemArray[i]).addClass("yellowBkgd").addClass("highLighted"))
}
}
else{
$(".highLighted").css("background","none")
}
}
If you look at the code below "//check to see if we need to do a recount on the array length. ", you'll see where I'm stripping out the text nodes based off of the display and whether or not the object is defined. I'm checking the length instead of undefined because the typeof == undefined wasn't working at all for some reason. Apparently, things are still slipping by though.
Any idea why I'm still getting undefined objects in the array?
My apologies for such a big post!
Thanks in advance
I've modified your eoTextSearch() function to remove dependencies on global variables in exchange for closures:
$.fn.extend({
// helper function
// recurses into a DOM object and calls a custom function for every descendant
eachDescendant: function (callback) {
for (var i=0, j=this.length; i<j; i++) {
callback.call(this[i]);
$.fn.eachDescendant.call(this[i].childNodes, callback);
}
return this;
},
// your text search function, revised
eoTextSearch: function () {
var text = document.createTextNode("test").textContent
? "textContent" : "innerText";
// the "matches" function uses an out param instead of a return value
var matches = function (pat, outArray) {
var isRe = typeof pat.test == "function";
return function() {
if (this.nodeType != 3) return; // ...text nodes only
if (isRe && pat.test(this[text]) || this[text].indexOf(pat) > -1) {
outArray.push(this.parentNode);
}
}
};
// this is the function that will *actually* become eoTextSearch()
return function (stringOrPattern) {
var result = $(); // start with an empty jQuery object
this.eachDescendant( matches(stringOrPattern, result) );
return result;
}
}() // <- instant calling is important here
});
And then you can do something like this:
$("body").eoTextSearch("foo").filter(function () {
return $(this).closest("tr").is(":visible");
});
To remove unwanted elements from the search result. No "recounting the array length" necessary. Or you use each() directly and decide within what to do.
I cannot entirely get my head around your code, but the most likely issue is that you are removing items from the array, but not shrinking the array afterwards. Simply removing items will return you "undefined", and will not collapse the array.
I would suggest that you do one of the following:
Copy the array to a new array, but only copying those items that are not undefined
Only use those array items that are not undefined.
I hope this is something of a help.
Found the answer in another post.
Remove empty elements from an array in Javascript
Ended up using the answer's second option and it worked alright.

Categories

Resources