Crawlling html and save json - javascript

im crawlling a html page, and is working fine but im having a issue, when im looping a rows from a table, and saving it in a json file, when finishing the loop instead of having 7 records i get the one 1 record and the last one from the loop.
My code:
finalResult[date] = {};
$(this).find('tbody tr').each(function (i, el) {
var $tds = $(this).find('td')
var counter = i +1;
$tds.each(function(index, element){
var $th = $(this).closest('table').find('th').eq($(this).index());
if($th.text() != ""){
var temp = { [counter] : $(this).text()};
finalResult[date][$th.text()] = { ...temp };
}
});
});
Im getting this result:
{
'Satuday, 31 Jan 2021': { PTM: { '7': '402 - 1' }, PT: { '7': '905 - 2' } }
}
When it should be like:
{
'Satuday, 31 Jan 2021': { PTM: { '1': '442 - 1','2': '442 - 1',.... ,'6': '402 - 1','7': '402 - 1' }, PT: { '1': '442 - 1','2': '442 - 1',.... ,'6': '402 - 1','7': '905 - 2' } }
}

I'm looping throught tbody tr and getting the text from "td"
Hem... okay. Below is just a guess...
Just reading the code without any HTML to rely on, I still have to suggest.
finalResult[date] = {};
$(this).find('tbody tr').each(function (i, el) {
// That is all td for one row
var $tds = $(this).find('td')
// So that is a row counter
var counter = i +1;
// Now looping tds of ONE row
$tds.each(function(index, element){
// Retreiving the corresponding column element (for the column name)
var $th = $(this).closest('table').find('th').eq($(this).index());
if($th.text() != ""){
// If not already existing, set that as an empty object
// If undefined, it set an empty object
// If existing, it does not change anything
finalResult[date][$th.text()] = finalResult[date][$th.text()] || {};
// The td text as an object {column+number:"text"}
var temp = { [counter] : $(this).text()};
// "merge" that new "td object" to the existing column object
finalResult[date][$th.text()] = { ...finalResult[date][$th.text()], ...temp };
}
});
});
In your code, finalResult[date][$th.text()] = { ...temp }; was just overwriting the previous object...

Related

how to read the selected option in the multiple dropdown list in the table?

On the click of submit button, I want to send all the data by ajax call to the server. I'm trying to get the selected Text of dropdown list, it gives the text of first dropdown list for each iteration.
JSFiddle https://jsfiddle.net/L7xy2kjz/10/.
This is the result of what I tried :
ScoreCard={"Heading":"pawar","parameters":[{"Name":"nikita ","Raiting":"ME","Score":"0"},{"Name":"mayuri","Raiting":"ME","Score":"0"}]},{"Heading":" schoool","parameters":[{"Name":"sss","Raiting":"ME","Score":"0"}]}
In the above code even after selecting the different options from the dropdown ie. "Raiting":"ME" . but the output displays the Text of first dropdown.
function GetObservationReview() {
var parameters = {}, status;
var ObservationArray = [];
$('#ObservationEntry, .tblObservation').each(function () {
var item = $(this).closest("tr").find('td'); //get each row
var hasclassparam = $(this).closest("tr").attr('name') === 'ObsevHeading';
if (status == 'Parameters' && $(this).attr('name') === 'ObsevHeading') { //if next tr is heading then push whole object in array till first heading
metrics = {
'Heading': Heading1,
'parameters': paramarray // paramNewArray
//work in process
}
var stringyfydata = JSON.stringify(metrics);
ObservationArray.push(stringyfydata);
metrics = {};
paramarray = [];
}
if ($(this).attr('name') === 'ObsevHeading') { //if the current row having name as heading
status == 'heading';
$.each(item, function (key, value) {
if (key == 0) {
Heading1 = ($(value).text());
}
//else if (key == 1) {
// TotalWeightage = ($(value).text());
//}
});
}
if ($(this).attr('name') === 'ObsvParameters') { //read parameters
status = 'Parameters';
var e = document.getElementById("dropDownLevelChangetrue");
var strUser = e.options[e.selectedIndex].text;
var islastchild = $(this).closest("tr").is(":last-child"); //last child
MyLevels = {}; i = 1;
$.each(item, function (key, value) {
if (key == 0) {
parametername = ($(value).text());
}
if (key == 1) {
param_Raiting = (strUser);
}
if (key == 2) {
para_Score =($(value).text());
}
});
parameters = {
"Name": parametername,
"Raiting": param_Raiting,
"Score": para_Score
}
paramarray.push(parameters);
if (islastchild === true) { // if row is last row add whole object in data
metrics = {
'Heading': Heading1,
'parameters': paramarray //parameter array that stores Paameter name and its weightage
}
var stringyfydata = JSON.stringify(metrics);
ObservationArray.push(stringyfydata); //pushing whole object in data1 array
paramarray = [];
metrics = {};
}
}
});
alert("ScoreCard=" + ObservationArray);
return ObservationArray;
}
The expected result :
ScoreCard={"Heading":"pawar","parameters":[{"Name":"nikita ","Raiting":"EE","Score":"0"},{"Name":"mayuri","Raiting":"ME","Score":"0"}]},{"Heading":" schoool","parameters":[{"Name":"sss","Raiting":"NI","Score":"0"}]}
I think you are always taking value from the same element in these lines
var e = document.getElementById("dropDownLevelChangetrue");
var strUser = e.options[e.selectedIndex].text;
Try to get them by name or something. getById always gets the first one in DOM node and ends

JSON Split - Place array text into li during interval

My task is to take the 3 different color lists in the jsonObj and place them into a <ul>. They should only appear one at a time, every second. For the sake of the fiddle, I put it to every 5 seconds.
I haven't gotten to the 2nd or 3rd list of colors yet because while I can list out my 1st color list, they're appending outside of the listItem I've created for them. The code it spits it is:
var jsonObj = '{"one":["red","green","blue"], "two":["red","green","blue"], "three":["orange","purple","hotpink"]}',
object = JSON.parse(jsonObj),
cOne = object.one,
cTwo = object.two,
cThree = object.three,
i = 0,
timer;
$('body').append('<ul/>');
timer = setInterval(function() {
$.each(cOne, function() {
var list = $('body ul'),
listItem = $(list).append('<li>'),
html = $(listItem).append(cOne[i]);
if (i < cOne.length) {
i++;
$(cOne[i]).split("");
list.append(html);
} else if (i = cOne.length) {
i = 0;
}
});
}, 5 * 1000);
timer;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Also available at https://jsfiddle.net/ep76ba3u/
What it does:
<ul>
<li></li>
"red"
<li></li>
"blue"
</ul>
What it should look like:
<ul>
<li>red</li>
<li>blue</li>
</ul>
I've tried rearranging it all. I've tried using wrap, innerWrap. I've tried just using text() and a few other methods. I started working on it at 3am and its 5am now... brain is fried. Any idea how to get this moving is appreciated.
You can not append partial html, that's why this $(list).append('<li>') is immediately closing the <li>.
And you should not modify the markup in a loop. It's obnoxious and unperformant.
Check out this approach to your code:
var jsonObj = '{"one":["red","green","blue"], "two":["red","green","blue"], "three":["orange","purple","hotpink"]}',
object = JSON.parse(jsonObj),
iteration = 0,
timer;
$('body').append('<div id=container>');
//a few utilities, because I don't want to repeat myself all over the place:
var string = value => value == null ? "" : String(value);
var wrapInNode = nodeName => value => `<${nodeName}>${ string(value) }</${nodeName}>`;
//here I create a few utility-methods that will build my markup:
var li = wrapInNode('li');
var ul = wrapInNode('ul');
var header = wrapInNode('h4');
timer = setInterval(function() {
//building the complete markup and adding it at once
var blocks = [],
//how many rows should I show in this iteration
numRowsLeft = ++iteration,
//getting this result is just a nice sideeffect of using `every()` instead of `forEach()`
//to short-curcuit the loop
done = Object.keys(object)
.every(function(key) {
//this line makes the title to be added with as a distinct iteration and not with the first item,
//check out what happens when you remove it
--numRowsLeft;
var rows = object[key]
//shorten the Array to numRowsLeft, if necessary
.slice(0, numRowsLeft)
//wrap each item in a li-node with my predefined utility-function
.map(li);
numRowsLeft -= rows.length;
//building the markup for this block
blocks.push(header(key) + ul(rows.join("")));
//here I'm short circuiting the loop. to stop processing the other keys on Object
return numRowsLeft > 0;
});
$('#container').html(blocks.join(""));
if (done) {
clearInterval(timer);
}
}, 1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
And showing the header all the time while only adding the points:
var jsonObj = '{"one":["red","green","blue"], "two":["red","green","blue"], "three":["orange","purple","hotpink"]}',
object = JSON.parse(jsonObj),
iteration = 0,
timer;
$('body').append('<div id=container>');
var string = value => value == null ? "" : String(value);
var wrapInNode = nodeName => value => `<${nodeName}>${ string(value) }</${nodeName}>`;
var li = wrapInNode('li');
var ul = wrapInNode('ul');
var header = wrapInNode('h4');
timer = setInterval(function() {
var numRowsLeft = ++iteration,
blocks = Object.keys(object)
.map(function(key) {
var rows = object[key]
.slice(0, numRowsLeft)
.map(li);
numRowsLeft -= rows.length;
return markup = header(key) + ul(rows.join(""));
});
$('#container').html(blocks.join(""));
// If I'd had room to show even more rows, then I' done
if (numRowsLeft > 0) {
clearInterval(timer);
}
}, 1000);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
I feel compelled to put in an answer which should perform better by cache of the jQuery objects and processes the objects and each color in them, hitting DOM once for each color.
var jsonObj = '{"one":["red","green","blue"], "two":["red","cyan","darkblue"], "three":["orange","purple","hotpink"]}',
objects = JSON.parse(jsonObj);
// set timer values
var basetime = 1000;
var delaytime = basetime;
// cache the ul list
var myul = $('<ul/>').appendTo('body');
//process outer objects
$.each(objects, function(key, item) {
// process color array held in item
$.each(item, function(index, color) {
setTimeout(function() {
$('<li/>').text(color).css('color', color).appendTo(myul);
}, delaytime);
delaytime = delaytime + basetime;
});
});
Test it out here https://jsfiddle.net/MarkSchultheiss/yb1w3o73/
var jsonObj = '{"one":["red","green","blue"], "two":["red","green","blue"], "three":["orange","purple","hotpink"]}',
object = JSON.parse(jsonObj),
cOne = object.one,
cTwo = object.two,
cThree = object.three,
i = 0,
timer;
$('body').append('<ul>');
var i = 0;
timer = setInterval(function() {
if (i === cOne.length - 1) clearInterval(timer);
$('body ul').append('<li>');
$('body ul li').last().text(cOne[i]);
i++;
}, 1000);

Filter a child picklist in CRM 2011

I'm trying to convert javascript code from CRM 4.0 to CRM 2011.
I'm having problems with a picklist filter.
My function is on the onchange of the parent picklist. It works the first time but the second it erase everything from my child picklist.
This is the part where I suppose to reset the picklist
if(!oSubPicklist.originalPicklistValues)
{
oSubPicklist.originalPicklistValues = oSubPicklist.getOptions();
}
else
{
oSubPicklist.getOptions = oSubPicklist.originalPicklistValues;
oSubPicklist.setOptions = oSubPicklist.originalPicklistValues;
}
And this is the part where i remove all the option not related:
oTempArray is an array with the options that i want to keep. If a check the "oSubPicklist.getOptions.length" the value is the same that my original picklist.
for (var i=oSubPicklist.getOptions.length; i >= 0;i--)
{
if(oTempArray[i] != true)
{
Xrm.Page.getControl("new_product").removeOption(i);
}
}
Ideas?
Edit: I solved declaring a global var with the originalPickList in the onLoad event and:
oSubPicklist.clearOptions();
for (var i=0; i< oSubPicklist.originalPicklistValues.length; i++)
{
for (var j=0; j< oDesiredOptions.length; j++)
{
if (i == oDesiredOptions[j])
{oSubPicklist.addOption(oSubPicklist.originalPicklistValues[i]);}
}
}
Your code is not very clear to me: May be you could paste all your function code for better understanding but:
This is how you get the options from PickList in CRM 2011
var myOptionSet = Xrm.Page.ui.controls.get("new_product") //get Control
var optionsSet = myOptionSet .getAttribute().getOptions(); //get Options
preferredTimeOptionSet.clearOptions(); //Clear all options
//Create a new Option
var opt1 = new Option();
opt1.text = "one";
opt1.value = 1;
//Add Option
myOptionSet.addOption(opt1);
//Remove Option
myOptionSet.removeOption(1);
Good Example here
Here is another way to do Parent/Child picklists:
function dynamicDropdown(parent, child) {
filterPicklist(parent, child);
}
function parentListFilter(parent, id) {
var filter = "";
if (getParentCode(parent) != "") {
filter = getParentCode(parent);
} else {
// No [ ] match
}
return filter;
}
function filterPicklist(parent, child) {
var parentList = Xrm.Page.getAttribute(parent).getValue();
var childListControlAttrib = Xrm.Page.getAttribute(child);
var childListOptions = childListControlAttrib.getOptions();
var childListControl = Xrm.Page.getControl(child);
var codeToFilterListOn = parentListFilter(parent, parentList);
if (codeToFilterListOn != "") {
childListControl.clearOptions();
for (var optionIndex in childListOptions) {
var option = childListOptions[optionIndex];
// Ignore xx and check for Match
if (option.text.substring(0, 2) != "xx" && option.text.indexOf(codeToFilterListOn) > -1) {
childListControl.addOption(option);
}
}
} else {
// Didn't match, show all?
}
}
function getParentCode(parent) {
//Get Parent Code Dynamically from inside [ ]
var filter = "";
var parentValue = Xrm.Page.getAttribute(parent).getText();
if (parentValue && parentValue.indexOf("]") > -1) {
var parentCode = parentValue.substring(parentValue.indexOf("[") + 1, parentValue.indexOf("]"));
if (parentCode) {
filter = parentCode + " | ";
} else {}
}
return filter;
}
See more here: Parent/Child

Extracting data form another section with same ID (Appcelerator)

I have the following JSON: (its simplified a bit for you)
{ returnJSON = {
studentDataVOs = {
finalGrades = (
{
grade = A;
percent = 100;
sectionid = 7744;
reportingTermId = 801;
},
{
grade = B+;
percent = 89;
sectionid = 7745;
reportingTermID = 801;
});
reportingTerms = (
{
id = 801;
title = S1;
},
{
id = 802;
title = S2;
});
sections = (
{
id = 7744;
termID = 801;
courseTitle = Physics;
courseCode = 88A;
},
{
id = 7745;
termID = 801;
courseTitle = Government;
courseCode = 90B;
});
};
};
}
I am building an app using Appcelerator Titanium that displays a table view with the data hopefully showing the following:
Physics (88A) - S1 (Grade: A, 100%)
Government (90B) - S1 (Grade: B+, 89%)
...and so on...
I have the table view set up and the following code extracts the data from the sections and puts it in the labels of the table view:
var response = JSON.parse(response);
var sections = response.returnJSON.studentDataVOs.sections;
for (i=0;i<sections.length;i++) {
var courseName = sections[i].courseTitle;
var courseCode = sections[i].courseCode;
}
What I cannot figure out is how to go about fetching the grade, and term title for each individual class. As you can see, the data for each section contains an ID and termID, which direct me to a section in the finalGrades and reportingTerms that contains the ID or termID, where I need to fetch the final grades, percents, and term titles.
Can anyone help me with this? I have been trying on and off for two days trying to figure this out...
You should create indexes for each field you've listed. It's pretty simple:
//for example you have user list
var users = [{
id : 1, email : 'user#gmail.com',
nickname : 'John'
}, {
id : 2, email : 'user#stackoverflow.com',
nickname : 'Peter'
}];
//and you need to query user by his email, id and nickname
//first, create 3 index list
var usersIdIndex = {}, usersEmailIndex = {},
usersNicknameIndex = {};
//then fill them
users.forEach(function(user){
usersIdIndex[user.id] = user;
usersEmailIndex[user.email] = user;
usersNicknameIndex[user.nickname] = user;
});
//now you can get users by any of this fields
//for example
console.log(usersIdIndex[2].nickname== 'Peter');
console.log(usersNicknameIndex['John'].email == 'user#gmail.com');
Sections -> Final Grades
In the sections list, I would pass a variable in the tablerow that I could use to query for the next set of data. You need the section id to associate the data with the data in the final grade, so I would add it to my table row.
When creating your table:
// This loop to loop through the data.
function getSections(_args){
var response = JSON.parse(response);
var sections = response.returnJSON.studentDataVOs.sections;
for (i=0;i<sections.length;i++) {
createMyRow({
courseName: sections[i].courseTitle,
courseCode: sections[i].courseCode,
sectionId: sections[i].id
});
}
}
// This function creates the rows for the table
function createMyRow(_args){
// the sectionId is now included in the tableRow and can be used later for your
// next query.
// allows the sectionId value is now can be queried when a user clicks it
// through e.rowData.
var tableRow = Ti.UI.createTableViewRow({
sectionId: _args.sectionId
});
var title = Ti.UI.createLabel({
text: _args.courseName
});
tableRow.add(title);
return tableRow;
}
var tableView = Ti.UI.createTableView();
var data = [];
function refreshTable()
data = getSections();
var rows = [];
for( var i = 0; i<data.length; i++){
rows.push(createMyRow(data[i]);
}
tableView.setData(rows);
}
// this passes the value of the sectionId so you can use it to look up your next section.
tableView.addEventListener('click', function(e){
getFinalGrades({
sectionId: e.rowData.sectionId
})
});
function getFinalGrades(_args){
var finalGrades = response.returnJSON.studentDataVOs.finalGrades
var data = [];
for (i=0;i<finalGrades.length;i++) {
if(finalGrades[i].sectionId == _args.sectionId){
data.push({
grade: finalGrades[i].grade,
percent: finalGrades[i].percent
});
}
}
return data;
}
I hacked this together rather quickly looking at some of my code examples. At the end of the getFinalGrades function, you would have an array of finalGrades that were only from sectionId you clicked.

Find DOM-element that occurs the most

A container div.example can have different 1st-level child elements (section, div, ul, nav, ...). Quantity and type of those elements can vary.
I have to find the type (e.g. div) of the direct child that occurs the most.
What is a simple jQuery or JavaScript solution?
jQuery 1.7.1 is available, although it should work in IE < 9 (array.filter) as well.
Edit: Thank you #Jasper, #Vega and #Robin Maben :)
Iterate through the children using .children() and log the number of element.tagNames you find:
//create object to store data
var tags = {};
//iterate through the children
$.each($('#parent').children(), function () {
//get the type of tag we are looking-at
var name = this.tagName.toLowerCase();
//if we haven't logged this type of tag yet, initialize it in the `tags` object
if (typeof tags[name] == 'undefined') {
tags[name] = 0;
}
//and increment the count for this tag
tags[name]++;
});
Now the tags object holds the number of each type of tag that occurred as a child of the #parent element.
Here is a demo: http://jsfiddle.net/ZRjtp/ (watch your console for the object)
Then to find the tag that occurred the most you could do this:
var most_used = {
count : 0,
tag : ''
};
$.each(tags, function (key, val) {
if (val > most_used.count) {
most_used.count = val;
most_used.tag = key;
}
});
The most_used object now holds the tag used the most and how many times it was used.
Here is a demo: http://jsfiddle.net/ZRjtp/1/
Edit: I think a jQuery function like below should be more useful..
DEMO
$.fn.theMostChild = function() {
var childs = {};
$(this).children().each(function() {
if (childs.hasOwnProperty(this.nodeName)) {
childs[this.nodeName] += 1;
} else {
childs[this.nodeName] = 1;
}
});
var maxNode = '', maxNodeCount = 0;
for (nodeName in childs) {
if (childs[nodeName] > maxNodeCount) {
maxNode = nodeName;
maxNodeCount = childs[nodeName];
}
}
return $(maxNode);
}
And then you can,
$('div.example').theMostChild().css('color', 'red');
A function like below should give you the count of child elements, from which you can get the max count. See below,
DEMO
$(function () {
var childs = {};
$('div.example').children().each(function () {
if (childs.hasOwnProperty(this.nodeName)) {
childs[this.nodeName] += 1;
} else {
childs[this.nodeName] = 1;
}
});
for (i in childs) {
console.log(i + ': ' + childs[i]);
}
});
That is not possible without some information about the expected types of child nodes.
EDIT : It is possible as Jasper pointed out that we need not know the tag names before hand. The following works in case you're looking only within a specific set of selectors.
var selectorArray = ['div', 'span', 'p',........]
var matches = $(div).children(selectorArray.join());
var max = 0, result = [];
$.each(selectorArray, function(i, selector){
var l = matches.filter(selector).length;
if(l > max){
max = l;
result[max] = selector;
}
});
result[max] gives you the tag name and max gives you the occurrence count

Categories