CasperJS each then next (future) value of response array - javascript

im using eachThen() method of CasperJS and I need to know the value of the next iteration item.
I have items like this :
array = [
[22,"blah"],
[22,"blah"],
[23,"blah"],
[24,"blah"],
[24,"blah"],
[24,"blah"]
]
I'm generating one file per group of items (grouped by [0]) .
My first approach was to compare the actual item with the previous item at the beginning of the iteration , and if [0] is different generate the file, like this :
//previousItem was initilizated = to actualItem
casper.eachThen(array , function (response) {
var actualItem = response.data
casper.then(function(){
if(actualItem[0] != previousItem[0]){
var filename = previousItem[0]+"file.html"
var f = fs.open(filename, 'a');
f.write(stdFile);
f.close();
previous = actualItem
}
});
//operations that prepares stdFile to be created
Problem appears at the end of the cycle, as im comparing actual with previous, the last group will not generate any files (of course, the 2 last items will have the same [0], and after that the cycle will end)
My solution here is to ask for the next item instead of the previous, and generate the file at the end of each iteration , but I dont know how to tell Casper to give me the item of actualItem+1 in the array.
I will try to fix this iterating the same array inside in paralel and returning the value of actual+1 , but maybe there is a way to do it using response variable.
The result must be 3 files : 22file.html , 23file.html and 24file.html
There are a lot of requests to make
, so I need to win any second I can.
If you have another approach to achieve this please let me know.
PS: Sorry for my english, its not my native language
Thanks

My first approach was too complicated, probably because I didnt sleep so much these days.
This is what I did :
cajIndex = 0;
//this block generates the file if actualItem (or actualCajero is the same) is not undefined and the actualItem[0] is not the same as the next item
if (actualCajero != undefined)
{
if (actualCajero[0] != cajerosArray[cajIndex][0]){
casper.then(function(){
var filename = "Ventas local"+" "+nombreLocal+"_"+actualDay[1]+"-"+actualDay[2]
stdFile = '<h1>'+filename+'</h1> <table border="1">'+ stdTable + '</table>';
this.echo("generando archivo "+filename);
var f = fs.open(filename+".xls", 'a');
f.write(stdFile);
f.close();
stdTable = "";
stdFile = "";
});
}
}
//after this i do my operations , ask again for file creating at the end but now if the next item is undefined, if it is undefined creates the file then
cajIndex++
and that solves everything, the key was declaring that index at 0 and asking for file creating before assigning actualItem to response, and then ask again at the end for the last item.
Hope it helps

Related

How to update sequentially in order in different rows and insert a new one?

I don't really know how to approach this, thing is, I'm developing a web application and in a section I need to assign projects to other developers, every assignment/project will have a priority of how important it is. Priority 1 is the highest (more important), and priority 5 is lowest (less important).
What the system has to do is, when I add a new priority 1 (or any other priority), if there are other priorities and a priority 1, move the others down (P1 = P2, P2 = P3, P3 = P4) and add the new one as P1.
I made a little piece of code (making everything manually that will only work once but is just for you to see what I want)
//PHP CODE
//prioridad = "P1" from a button
$prioridad = validacion::limpiar_cadena($_POST['prioridad']);
$estado = "";
$pes = array();
//I get all the priorities from my user and save them in this array
//Saving an array of the user's priorities
while ($row = $resultado->fetch_assoc()){
$pes[] = $row["prioridad"];
}
//Replace current priorities with their new one (just once)
if (in_array($prioridad, $pes)){
if (in_array("P5", $pes)){
$estado = "lleno";
}
//Make priority 4 = priority 5 and same for all
//This user just had the first 3 priorities,so this one did nothing but the others updated succesfully just for this example
if (in_array("P4", $pes)){
$upd= $conexion->prepare("UPDATE asignarproyectousuario SET prioridad = 'P5' WHERE idUsuario = 1 AND idProyecto = 32");
$upd->execute();
}
if (in_array("P3", $pes)){
$upd= $conexion->prepare("UPDATE asignarproyectousuario SET prioridad = 'P4' WHERE idUsuario = 1 AND idProyecto = 2");
$upd->execute();
}
if (in_array("P2", $pes)){
$upd = $conexion->prepare("UPDATE asignarproyectousuario SET prioridad = 'P3' WHERE idUsuario = 1 AND idProyecto = 1");
$upd->execute();
}
if (in_array("P1", $pes)){
$upd= $conexion->prepare("UPDATE asignarproyectousuario SET prioridad = 'P2' WHERE idUsuario = 1 AND idProyecto = 3");
$upd->execute();
}
$insert = $conexion->prepare("INSERT asignarproyectousuario(idProyecto, idUsuario, prioridad) VALUES(4, 1, ?)");
$insert->bind_param("s", $prioridad);
$insert->execute();
}
I tried using arrays and adding a value of one to the current priority but I don't know how to make it work, separate the array and assign every value to a row in the database.
I also found queues that make exactly that "movement" of adding one priority and move the others in order, but I haven't found much documentation about it.
This is the example I saw:
$queue = new SplQueue();
$queue->enqueue('prioridad1');
$queue->enqueue('Prioridad2');
$queue->enqueue('Prioridad3');
$queue->unshift('prioridad1');
$queue->rewind(); // always rewind the queue/stack, so PHP can start from the beginning.
while($queue->valid()){
echo $queue->current()."\n"; // Show the first one
$queue->next(); // move the cursor to the next element
}
echo "\n"."\n"."\n";
var_dump($queue);
If you could give me an idea of how to do it or a different example would be very helpful.
Thanks in advance and if my english is not good enough I can try to explain it better.
technique is simple >
you need to know how JSON works
add an Extra column (text) in mysql Table >
store JSON array in that column Like >
[{"TaskName":"XYX","AssignDate":"AnyDate","Priority":"High","PriorityCount":"50"}]
add extra array in JSON / Update array whenever require
itarate the array that finds ("Priority":"High" AND "PriorityCount": "" // highest)
this might help > Getting max value(s) in JSON array

Previous array data gets printed to string

this is related to the code from my previous question, but this new problem is related to printing array data into a string, which then is passed on to the text on my page
My page "rolls" genetic data, which is presented as gene abbreviations. Under the abbreviations, i want to list the gene names. What happens is that the array values from a previous "roll" gets printed underneath a new roll, meaning that the array that contains the gene names is always one "roll" behind.
i suspect it has to do with the fact that im using $.getJSON, but I'm not sure how to use the current data instead of the previous data.
here is what my code for this part looks like:
$.getJSON('genes.json', function(data){
$.each(data.gCommon, function(i, g) {
if(genoArray.includes(g.rec) || genoArray.includes(g.dom)){
phenoArray.push(g.phen);
}
});
getPheno(phenoArray);
});
function getPheno(phenoArray){
console.log(genoArray);
console.log(phenoArray);
$phenoString = phenoArray.join(", ");
}
$babyGenes = genoArray.join("/");
if(genoArray.length > 1){
$babyPheno = $phenoString.replace(/("[^"]+"|\w+)$/, "and $1");
} else {
$babyPheno = $phenoString;
}
console.log("Baby: " + $babyGenes);
console.log("Pheno: " + $babyPheno);
any advice helps, thanks in advance!!

Function returning object instead of Array, unable to .Map

I'm parsing an order feed to identify duplicate items bought and group them with a quantity for upload. However, when I try to map the resulting array, it's showing [object Object], which makes me think something's converting the return into an object rather than an array.
The function is as follows:
function compressedOrder (original) {
var compressed = [];
// make a copy of the input array
// first loop goes over every element
for (var i = 0; i < original.length; i++) {
var myCount = 1;
var a = new Object();
// loop over every element in the copy and see if it's the same
for (var w = i+1; w < original.length; w++) {
if (original[w] && original[i]) {
if (original[i].sku == original[w].sku) {
// increase amount of times duplicate is found
myCount++;
delete original[w];
}
}
}
if (original[i]) {
a.sku = original[i].sku;
a.price = original[i].price;
a.qtty = myCount;
compressed.push(a);
}
}
return compressed;
}
And the JS code calling that function is:
contents: compressedOrder(item.lineItems).map(indiv => ({
"id": indiv.sku,
"price": indiv.price,
"quantity": indiv.qtty
}))
The result is:
contents: [ [Object], [Object], [Object], [Object] ]
When I JSON.stringify() the output, I can see that it's pulling the correct info from the function, but I can't figure out how to get the calling function to pull it as an array that can then be mapped rather than as an object.
The correct output, which sits within a much larger feed that gets uploaded, should look like this:
contents:
[{"id":"sku1","price":17.50,"quantity":2},{"id":"sku2","price":27.30,"quantity":3}]
{It's probably something dead simple and obvious, but I've been breaking my head over this (much larger) programme till 4am this morning, so my head's probably not in the right place}
Turns out the code was correct all along, but I was running into a limitation of the console itself. I was able to verify this by simply working with the hard-coded values, and then querying the nested array separately.
Thanks anyway for your help and input everyone.
contents: compressedOrder(item.lineItems).map(indiv => ({
"id": indiv.sku,
"price": indiv.price,
"quantity": indiv.qtty
}))
In the code above the compressedOrder fucntion returns an array of objects where each object has sku, price and qtty attribute.
Further you are using a map on this array and returning an object again which has attributes id, price and quantity.
What do you expect from this.
Not sure what exactly solution you need but I've read your question and the comments, It looks like you need array of arrays as response.
So If I've understood your requirement correctly and you could use lodash then following piece of code might help you:
const _ = require('lodash');
const resp = [{key1:"value1"}, {key2:"value2"}].map(t => _.pairs(t));
console.log(resp);
P.S. It is assumed that compressedOrder response looks like array of objects.

Populating table with textbox value from previous HTML page

I have some JS that stores the name and value of selected checkboxes on one page and then, on a button click, adds this data to a table on page 2.
This works, but now I am looking to do the same for a textbox containing a number. Specifically, I'm looking to take the value entered by the user and add this to a cell in the table. What would be the best way to approach this? Add to the existing function or create a separate on button click function specifically for the textbox value?
I have added a screenshot of the HTML table on page 2 along with where I would like the textbox value to go (highlighted with a red rectangle).
Here's what I have so far:
HTML for textbox (page 1):
<div class="selecttier">
<h1>5. Number of Clicks</h1>
<input id="numberofclickstextbox" name="numberofclicks" type="text" value="0" data-total="0" oninput="calculatetier()" />
</div>
JS on page 1:
$('#sales_order_form_button').click(function() {
let table_info = [];
$('input[type=checkbox]').each(
function(index, value) {
if($(this).is(':checked')) {
table_info.push(
{
name: $(this).attr('name'),
value: $(this).attr('value'),
}
);
}
});
let base64str=btoa(JSON.stringify(table_info));
window.location = "page2.html?table_data=" + base64str;
});
JS on page 2:
// Helper function
function getUrlParameter(name) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
var results = regex.exec(location.href);
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
};
// actual code
let table_data = getUrlParameter('table_data');
let data_from_page_1 = JSON.parse(atob(table_data));
for(let i = 0; i < data_from_page_1.length; i++){
let row = $("<tr></tr>");
let recordName = $("<td></td>").text(data_from_page_1[i].name);
let recordValue = $("<td></td>").text(data_from_page_1[i].value);
row.append(recordName, recordValue);
$('#output_table').append(row);
}
// code to sum CPC column
var sum1 = 0;
$("#output_table tr > td:nth-child(2)").each(
(_,el) => sum1 += Number($(el).text()) || 0
);
$("#sum1").text(sum1);
//datetime stamp
var dt = new Date();
document.getElementById("datetime").innerHTML = dt.toLocaleString();
Output HTML table (page 2):
<table id="output_table">
<tr>
<th>Name</th>
<th>Value</th>
<th>Number of Clicks</th>
</tr>
<tfoot>
<tr>
<th id="total" colspan="1">Total CPC:</th>
<td id="sum1"></td>
</tr>
</tfoot>
</table>
As stated in the #Manu Varghese comment, the way to go would be using sessionStorage or localStorage.
First, let's differentiate both. According to the Stack Overflow question "HTML5 Local storage vs Session Storage", we have the following answer:
localStorage and sessionStorage both extend Storage. There is no difference between them except for the intended "non-persistence" of sessionStorage.
That is, the data stored in localStorage persists until explicitly deleted. Changes made are saved and available for all current and future visits to the site.
For sessionStorage, changes are only available per tab. Changes made are saved and available for the current page in that tab until it is closed. Once it is closed, the stored data is deleted.
Considering they are used the same way and you must to choose between what better fits your case, I will proceed using sessionStorage.
For that, in the first page you must use:
sessionStorage.setItem("key", "value")
You may set the item right when you perceives a change, like in the input 'blur' event.
and when you land in the second page (right when jQuery calls its start event), you will retrieve your data using:
sessionStorage.getItem("key")
Take in mind that localStorage/sessionStorage can support a limited amount of data. Even if that limit is way bigger than URL, most browsers will store only 2.5MB to 10MB per origin, according to the browser implementation (you may test by yourself in the link recommended in MDN (Mozilla Development Network), http://dev-test.nemikor.com/web-storage/support-test/).
Also, you may want to avoid storing sensitive data in the storages, due to some some discussions about security, which seems not to be a complaint here.
Implementation in the given case
Your code can be modified in three steps:
Change the way you save the data to use the storage
Creates a JSON of an object containing the array, instead the make the JSON using the array itself. Then you can add more fields.
Load the JSON object and its fields (the array and the number).
Step 1 - Changing to sessionStorage
Just now you have your Javascript on page 1 creating an array of data and stringifying that data to a JSON string.
If you want to use the storage rather than the URL for all the data, just change these lines of code from:
let base64str=btoa(JSON.stringify(table_info));
window.location = "page2.html?table_data=" + base64str;
to the code that will save the data into a (local/session)Storage:
let jsonStr=JSON.stringify(table_info); // converts to JSON string
sessionStorage.setItem("oldData", jsonStr); // save to storage
window.location = "page2.html"; // navigate to other page
Notice that the storage can receive any string, but only strings, then we can remove the btoa function, but we must keep the stringify.
Step 2 -- Adding more data to save
Now you have one JSON that is an array of items. But what do you want is to include one more field, parallel to this array. Of course, you can't include it in the array, as it is a different thing. So, what we must to do is to create a JSON object which has a number field AND the array field itself.
Your function to create the array is all ok, then we will use the same "table_data" as the array and include it to a new JSON object:
let table_data = []; // the array you have
$('input[type=checkbox]').each(
... rest of code ...
); // the function that creates the array (I abbreviated it here)
// Creates an object with an array and a number
let jsonObj = {
table_data: table_data,
number_of_clicks: theNumberYouHave/* your variable with the number here */
};
// This is the bit above with CHANGES into variable names
// Instead of "table_data", now we save "jsonObj"
let jsonStr=JSON.stringify(jsonObj); // converts the "jsonObj" to a JSON string
sessionStorage.setItem("oldData", jsonStr);
window.location = "page2.html";
Remember to change "theNumberYouHave" to whatever your variable with the number is called. The you will append the number as a field of the JSON object.
In other words, this simply will create an structure like that:
{
number_of_clicks: 5216,
table_data: [
{ name: "...", value: "..."},
{ name: "...", value: "..."},
{ name: "...", value: "..."},
...
]
}
See? Your table_data is still there, but with a new sibling (number_of_clicks) inside an object.
Step 3 -- Loading data from page 1
For now, you have these two lines of code in page 2 to read data from page 1:
let table_data = getUrlParameter('table_data');
let data_from_page_1 = JSON.parse(atob(table_data));
What do you need there, is to simply replace the getUrlParameter function to read from the storage, and remove the atob function to reflect the changes we made in page 1, this way:
let jsonObj = sessionStorage.getItem("oldData"); // reads the string
let data_from_page_1 = JSON.parse(jsonObj); // parse the JSON string
let table_data = data_from_page_1.table_data; // grab the table data
let number_of_clicks = data_from_page_1.number_of_clicks; // grab the number
Now you are free to use the variable "table_data" like you did, and to use the "number_of_clicks" in the way you want to use it. It is the number passed from page 1, then you may set it to your table cell.
You have it with the unique ID "sum1", the you may just:
$("#sum1").text(number_of_clicks);
And you are done!
I highly recommend localStorage and sessionStorage to be used, as per this and this
Page 1 code full source
$('#next_page_button').click(function(){
let table_info = [];
// Do for checkboxes
$('.campaignstrategy input[type=checkbox]').each(
function(index, value){
if($(this).is(':checked')){
table_info.push(
{
name: $(this).attr('name'),
value: $(this).attr('value'),
type: 'checkbox'
}
);
}
});
$('.campaignstrategy input[type=text]').each(
function(index, value){
table_info.push(
{
name: $(this).attr('name'),
value: $(this).attr('value'),
type: 'text'
}
);
});
let base64str=btoa(JSON.stringify(table_info));
window.location = "page2.html?table_data=" + base64str;
});
Page 2 Code full source
// Helper function
function getUrlParameter(name) {
name = name.replace(/[\[]/, '\\[').replace(/[\]]/, '\\]');
var regex = new RegExp('[\\?&]' + name + '=([^&#]*)');
var results = regex.exec(location.href);
return results === null ? '' : decodeURIComponent(results[1].replace(/\+/g, ' '));
};
// actual code
let table_data = getUrlParameter('table_data');
let data_from_page_1 = JSON.parse(atob(table_data));
// clear table
$('#output_table').html("");
// generator checboxes
for(let i=0;i<data_from_page_1.length;i++){
if(data_from_page_1[i].type == "checkbox"){
let row = $("<tr></tr>");
let recordName = $("<td></td>").text(data_from_page_1[i].name);
let recordValue = $("<td></td>").text(data_from_page_1[i].value);
let recordCount = $("<td></td>").text("");
row.append(recordName, recordValue, recordCount); // not used but needed
$('#output_table').append(row);
}
}
// generate textboxes
for(let i=0;i<data_from_page_1.length;i++){
if(data_from_page_1[i].type == "text"){
let row = $("<tr></tr>");
let recordName = $("<td></td>").text("");
let recordValue = $("<td></td>").text("");
let recordCount = $("<td></td>").text(data_from_page_1[i].value);
row.append(recordName, recordValue, recordCount);
$('#output_table').append(row);
}
}
ANSWER:
What would be the best way to approach this?
window.localStorage - stores data with no expiration date
window.sessionStorage - stores data for one session

resolving a javascript and database table logic situation

When I query a database table, I get back values "yes" or "no" for records that represent whether an item is present or not (the item is the column name). I want to create a string that represents the products that are available by name (rather than what I am doing now "kitchen table =" + kitchenTable;
I am thinking this can be solved (poorly) by a series of if statements setting variables to either the product name or to "" and then include all variables in the string
var kt;
if (kitchenTable == yes) kt = "kitchen table";
else kt = "";
if (kitchenCabinet == yes) kc = "kitchen cabinet";
else ka = "";
output = kt + ', ' + kc;
There are about 50 items that can be presented to the user, is there a more efficient way of accomplishing this task?? One option is to change how values are entered into the datbase table such that instead of yes, its the item name but this seems like a poorer way to resolve the issue
Of course you don't give all the details about how do you make query so that is an imaginary mockup of a function simulating query
var available = [];
var result = query("kitchen table");
result === "yes" && ( available.push("kitchen table") );
......
var output = available.join();
What you want is actually built into javascript itself.
I would say using an object literal will really simply your life in this situation by organizing your code and turning it into a more readable format.
I would also recommend turning your server data into true and false as this is a standardized way to communicated a Boolean and allows for the method below to work as it does:
// From server response
var results = {
kitchenCabinet: true,
kitchenTable: true
}
// Use this for your storage of all related items
var kitchenProps = {
kitchenCabinet: 'kitchen cabinet',
kitchenTable: 'kitchen table'
}
// Reuse this function for each time your need a new category (masterBathroomProps...)
function getItemDataIfExists(results, hashTable){
'use strict';
var output = 'Your total is: ';
for (var item in results) {
if (!results.hasOwnProperty(item)) return;
if (results[item]) output += 'A '+hashTable[item]+' ';
}
return output;
}
getItemDataIfExists(results, kitchenProps);
Explanation:
You loop through a result set of an object containing keys names and true false values. In the loop, if the keyname's value is true, then use that keyname to access the properties (in this case a string of your choice. The "key" here is that the key names in each object must line up.
Here is a live demo:
http://codepen.io/nicholasabrams/pen/JXXbYz?editors=0010

Categories

Resources