Weird jQuery data() issue - Help? - php

jquery 1.6.2 / Firefox 6.0.1
OK I'm working on this shipment manager interface and when the page is loaded, each table row tr is assigned an id "shipment_XXXXX" where XXXXX is the id of the shipment from the database.
All the data regarding the shipment is, in PHP set to a multidimensional associative array which contains "shipmentItems" and "pkgs" among other things which are irrelevant. The shipmentItems object is a regular numeric array, where each element has several associative values such as "name", "qty", "price" so for example:
$shipmentItems[0]["name"] = "item 1";
$shipmentItems[0]["qty"] = 5;
$shipmentItems[0]["price"] = 20.00;
$shipmentItems[1]["name"] = "item 2";
$shipmentItems[1]["qty"] = 3;
$shipmentItems[1]["price"] = 5.00;
This array indicates all of the items that are part of this shipment in whole.
The other array pkgs is a list of each package in the shipment and each package has a packing_slip object/associative array. Example:
PACKAGE #1
$pkgs[0]['packing_slip'][0]['name'] = "item 1";
$pkgs[0]['packing_slip'][0]['qty'] = 3;
$pkgs[0]['packing_slip'][0]['price'] = 20.00;
$pkgs[0]['packing_slip'][1]['name'] = "item 2";
$pkgs[0]['packing_slip'][1]['qty'] = 1;
$pkgs[0]['packing_slip'][1]['price'] = 50.00;
PACKAGE #2
$pkgs[1]['packing_slip'][0]['name'] = "item 1";
$pkgs[1]['packing_slip'][0]['qty'] = 2;
$pkgs[1]['packing_slip'][0]['price'] = 20.00;
$pkgs[1]['packing_slip'][1]['name'] = "item 2";
$pkgs[1]['packing_slip'][1]['qty'] = 2;
$pkgs[1]['packing_slip'][1]['price'] = 50.00;
You'll see that the pkg array has the full shipment item list for each packing slip for each package. if you add the 0index qty from both packages you'll see that it adds up to the full shipment qty for that item line.
This set of data gets converted to a JSON string by php and tucked into a hidden form element within its corrosponding row.
After the page is loaded, jquery goes through each hidden json element, parses the json string to an object, the attaches the object to the TR.data('shipmentItems') and TR.data('pkgs') for each shipment in the list.
This is where things get funky...
I'm doing a function where the user can add a new package to the shipment. When they do this they are prompted to specify which package has how many quantities of each item in the whole shipment. They essentially lay out the packing slips.
The function they execute after they have mapped out the quantities, recreates the pkgs array(object) on the fly, which it gets from its rows .data('pkgs') container - and then re-attaches the pkgs object back to the data('pkgs') container.
I have logged the output of this function heavily and the quantities are all being assigned to the proper values see here:
var shipmentItems = $('#shipment_'+shipid).data('shipmentItems');
var pkgs = $('#shipment_'+shipid).data('pkgs');
var pkgnum = pkgs.length; // always returns one higher than last index.
// add new pkg to array
pkgs[pkgnum] = new Object();
pkgs[pkgnum].weight = weight;
console.log("("+pkgnum+") pkgs length: " + pkgs.length);
// overwrite packing slip data.
for(var x = 0; x < pkgs.length; x++) {
var curPS = new Array();
var curins = 0;
for(var y = 0; y < shipmentItems.length; y++) {
var curqty = parseInt($('#pkgqty-'+y+'-'+x).val());
curins += curqty * shipmentItems[y]['price'];
curPS.push(shipmentItems[y]);
console.log("["+y+"] before: " + curPS[y]['qty']);
curPS[y]['qty'] = curqty;
console.log("["+y+"] after: " + curPS[y]['qty']);
}
console.log(curPS[0]['qty'] + ' - ' + curPS[1]['qty']);
pkgs[x].packing_slip = curPS;
pkgs[x].insurance = curins;
}
// write pkgs data()
$('#shipment_'+shipid).removeData('pkgs');
$('#shipment_'+shipid).data('pkgs', pkgs);
The log output of the above is as follows:
(1) pkgs length: 2
[0] before: 3
[0] after: 2
[1] before: 4
[1] after: 3
2 - 3 // value of curPS[0]['qty'] and curPS[1]['qty'] for pkg#1 - pkgs[0] is set to curPS at this point.
[0] before: 2
[0] after: 1
[1] before: 3
[1] after: 1
1 - 1 // value of curPS[0]['qty'] and curPS[1]['qty'] for pkg#2 - pkgs[1] is set to curPS at this point.
This looks like it worked, right? Wrong. After the function completes I have a button I can push that prints out all the data() vars for a row. Not only are the qty value of every single pkg['packing_slip'][x] item set to 1, but if I look at the shipmentItems from this same object log, the qty values for all of the shipmentItems have also been reset to 1. Which is odd because at no point in the code does shipmentItems ever get overwritten and should still be the exact same as it was when the page loaded...
Anyone have any ideas whats going on here?

maybe it's because you pass shipmentItems by Reference - curPS.push(shipmentItems[y]);
Try to pass it by Value - curPS.push(shipmentItems[y].slice());

OK I ended up getting this working thanks to your (Alon) suggestion pointing me in the right direction. The slice() method did not work outright because the array elements I'm slicing out contained objects and so the deeper objects were still being passed as references rather than being copied. After some searching around I found the jQuery.extend() method was what I needed to copy the object arrays! Thanks again!

Related

filter data with php or sql?

I'm not sure if this is an anti-pattern or not, but it feels a bit convoluted, so I'd like to get your opinion on how these cases should be handled:
Let's say we have this data:
$sofas[0]['color'] = 'green';
$sofas[0]['pillows'] = 8;
$sofas[0]['pattern'] = 'moons';
$sofas[1]['color'] = 'green';
$sofas[1]['pillows'] = 8;
$sofas[1]['pattern'] = 'ducks';
$sofas[1]['footrest'] = 'small';
$sofas[2]['color'] = 'green';
$sofas[2]['pillows'] = 8;
$sofas[2]['pattern'] = 'stripes';
$sofas[2]['speakers'] = 'badass';
color, pillows and pattern comes from the database, whilst "footrest" and "speakers" have been added on by an api.
We can say for the sake of argument that there are 1250 different attributes that can be added by the api like "footrest" and "speakers".
We now want to load an some data from the database based on these attributes, like an image for example.
So we have a table that looks like this:
ID , attribute_value, image
1 , 'color_green' 'img0023',
2 , 'pillows_8' 'img003',
3 , 'pattern_moons' 'img002',
6 , 'pattern_ducks' 'img0083',
7 , 'footrest_small' 'img0058',
10 , 'pattern_stripes''img0073',
11 , 'speakers_badass''img00pluto'
etc , etc , etc;
So, the way I figure I can approach this two ways:
$sofaSQL="'color_green',
'pillows_8',
'pattern_moons',
'pattern_ducks',
'footrest_small',
'pattern_stripes',
'speakers_badass'";
$sql = "SELECT ID, attribute_value, image
FROM `example`
WHERE attribute_value IN ($sofaSQL)"
and then loop through the array and check if the key + '_' + value matches the rows in the recordset to see what images should be used for sofas[0], sofas[1] and sofas[2].
The other option I see would be to prep each sofa with a different sql statement, ie:
$sofaSQL="'color_green',
'pillows_8',
'pattern_moons';
-add images-
$sofaSQL="'color_green',
'pillows_8',
'pattern_ducks',
'footrest_small';
-add images-
$sofaSQL="'color_green',
'pillows_8',
'pattern_stripes',
'speakers_badass'";
-add images-
That seems simpler, but it doesn't feel right to hammer the database with a seperate request for each item in the array.
So, what would you recommend in this case? IS there a better way of dealing with attributes that are selected randomly/from an api?

How to send array in http get request

private void timer1_Tick(object sender, System.EventArgs e)
{
int iIdx;
int[] iData;
bool[] bData;
if (m_bRegister) // Read registers (4X references)
{
// read register (4X) data from slave
if (adamTCP.Modbus().ReadHoldingRegs(m_iStart, m_iLength, out iData))
{
m_iCount++; // increment the reading counter
txtStatus.Text = "Read registers " + m_iCount.ToString() + " times...";
// update ListView
label1.Text = HttpGet("http://127.0.0.1/misc/api1.php?value0=" + iData[0].ToString());
label2.Text = HttpGet("http://127.0.0.1/misc/api1.php?value1=" + iData[1].ToString());
label3.Text = HttpGet("http://127.0.0.1/misc/api1.php?value2=" + iData[2].ToString());
label4.Text = HttpGet("http://127.0.0.1/misc/api1.php?value3=" + iData[3].ToString());
label5.Text = HttpGet("http://127.0.0.1/misc/api1.php?value4=" + iData[4].ToString());
for (iIdx = 0; iIdx < m_iLength; iIdx++)
{
listViewModbusCur.Items[iIdx].SubItems[2].Text = iData[iIdx].ToString(); // show value in decimal
listViewModbusCur.Items[iIdx].SubItems[3].Text = iData[iIdx].ToString("X04"); // show value in hexdecimal
}
How do i send array using httpget method? The code on top show that i'm sending data one by one. I need to send it in array and retrieve it back in api,php so that i could insert it into database in one row. currently, it's 1 data for 1 row.
Here is a example to convert array to json in PHP
$arr=array(
"varl1"=>1,
"varl2"=>"example",
"varl3"=>3,
);
$json_arr=json_encode($arr);
Now you can send $json_arr
and then you can decode it using json_decode()
you should passing 'value0' become just one querystring, ex : value[]
so the url will become
http://127.0.0.1/misc/api1.php?value[]="+ iData[0].ToString()"&value[]="+ iData[1].ToString() and etc what you want to send it "
or you should use http_build_query to the param array data
the code you show is php ??
the api maybe php but the code style more like .NET c#
correct me if im wrong.
//Update Response
string[] param = new string[(how many your counter param)];
param [0] = "test0";
param [1] = "test1";
param [2] = "test2";
in my example i give you 3
string sParams = JsonConvert.SerializeObject(param) ;
HttpGet("http://127.0.0.1/misc/api1.php?value=" + sParams);

Using R, how to reference variable variables (or variables variable) a la PHP [revisited]

In a previous Using R, how to reference variable variables (or variables variable) a la PHP[post]
I asked a question about something in R analagous to PHP $$ function:
Using R stats, I want to access a variable variable scenario similar to PHP double-dollar-sign technique: http://php.net/manual/en/language.variables.variable.php
Specifically, I am looking for a function in R that is equivalent to $$ in PHP.
The get( response works for strings (characters).
lapply is a way to loop over lists
Or I can loop over and get the values ...
for(name in names(vars))
{
val = vars[[name]];
I still haven't had the $$ function in R answered, although the lapply solved what I needed in the moment.
`$$` <- function
that allows any variable type to be evaluated. That is still the question.
UPDATES
> mlist = list('four'="score", 'seven'="years");
> str = 'mlist$four'
> mlist
$four
[1] "score"
$seven
[1] "years"
> str
[1] "mlist$four"
> get(str)
Error in get(str) : object 'mlist$four' not found
> mlist$four
[1] "score"
Or how about attributes for an object such as mobj#index
UPDATES #2
So let's put specific context on the need. I was hacking the texreg package to build a custom latex output of 24 models of regression for a research paper. I am using plm fixed effects, and the default output of texreg uses dcolumns to center, which I don't like (I prefer r#{}l, so I wanted to write my own template. The purpose for me, to code this, is for me to write extensible code that I can use again and again. I can rebuild my 24 tables across 4 pages in seconds, so if the data change, or if I want to tweak the function, I immediately have a nice answer. The power of abstraction.
As I hacked this, I wanted to get more than the number of observations, but also the number of groups, which can be any user defined index. In my case it is "country" (wait for it, hence, the need for variable variables).
If I do a lookup of the structure, what I want is right there: model$model#index$country which would be nice to simply call as $$('model$model#index$country'); where I can easily build the string using paste. Nope, this is my workaround.
getIndexCount = function(model,key="country")
{
myA = attr(summary(model)$model,"index");
for(i in 1:length(colnames(myA)))
{
if(colnames(myA)[i] == key) {idx = i; break;}
}
if(!is.na(idx))
{
length(unique(myA[,idx]));
} else {
FALSE;
}
}
UPDATES #3
Using R, on the command line, I can type in a string and it gets evaluated. Why can't that internal function be directly accessed, and the element captured that then gets printed to the screen?
There is no equivalent function in R. get() works for all types, not just strings.
Here is what I came up with, after chatting with the R-bug group, and getting some ideas from them. KUDOS!
`$$` <- function(str)
{
E = unlist( strsplit(as.character(str),"[#]") );
k = length(E);
if(k==1)
{
eval(parse(text=str));
} else {
# k = 2
nstr = paste("attributes(",E[1],")",sep="");
nstr = paste(nstr,'$',E[2],sep="");
if(k>2) {
for(i in 3:k)
{
nstr = paste("attributes(",nstr,")",sep="");
nstr = paste(nstr,'$',E[i],sep="");
}
}
`$$`(nstr);
}
}
Below are some example use cases, where I can directly access what the str(obj) is providing... Extending the utility of the '$' operator by also allowing '#' for attributes.
model = list("four" = "score", "seven"="years");
str = 'model$four';
result = `$$`(str);
print(result);
matrix = matrix(rnorm(1000), ncol=25);
str='matrix[1:5,8:10]';
result = `$$`(str);
print(result);
## Annette Dobson (1990) "An Introduction to Generalized Linear Models".
## Page 9: Plant Weight Data.
ctl <- c(4.17,5.58,5.18,6.11,4.50,4.61,5.17,4.53,5.33,5.14);
trt <- c(4.81,4.17,4.41,3.59,5.87,3.83,6.03,4.89,4.32,4.69);
group <- gl(2, 10, 20, labels = c("Ctl","Trt"));
weight <- c(ctl, trt);
lm.D9 <- lm(weight ~ group);
lm.D90 <- lm(weight ~ group - 1); # omitting intercept
myA = anova(lm.D9); myA; str(myA);
str = 'myA#heading';
result = `$$`(str);
print(result);
myS = summary(lm.D90); myS; str(myS);
str = 'myS$terms#factors';
result = `$$`(str);
print(result);
str = 'myS$terms#factors#dimnames';
result = `$$`(str);
print(result);
str = 'myS$terms#dataClasses#names';
result = `$$`(str);
print(result);
After realizing the back-tick can be a bit tedious, I chose to update the function, calling it access
access <- function(str)
{
E = unlist( strsplit(as.character(str),"[#]") );
k = length(E);
if(k==1)
{
eval(parse(text=str));
} else {
# k = 2
nstr = paste("attributes(",E[1],")",sep="");
nstr = paste(nstr,'$',E[2],sep="");
if(k>2) {
for(i in 3:k)
{
nstr = paste("attributes(",nstr,")",sep="");
nstr = paste(nstr,'$',E[i],sep="");
}
}
access(nstr);
}
}

How to parse URL when using the pager plugin with AJAX

I am trying to use the tablesorter pager plugin with AJAX but run into som problemes (or limitations) when trying to handle the AJAX request in my php backend.
If eg. the table is set up with a default sorting of
sortList: [ [0,1], [1,0] ]
I will get a URL like this on my AJAX request:
page=0&size=50&filter=fcol[6]=batteri&sort=col[0]=1&col[1]=0
In my php back end I do a
$cur_sort = $_GET['sort']
and get
col[0]=1
So the last part is missing - I guess since it contains a & char.
How do I get the entire sort string?
That said how is the string col[0]=1&col[1]=0 best parsed? I need to extract the info that col 0 is to be sorter DESC and col 1 ASC.
You can try this;
parse_str($_SERVER['QUERY_STRING'],$data);
It will parse the url to an array;
Also; you should use empty [] instead of [1] and [0]
See more here: parse_str()
Example:
$str = "page=0&size=50&filter=fcol[6]=batteri&sort=col[0]=1&col[1]=0";
parse_str($str, $output);
echo $output['page']; // echo 0
And to answer your question; it is correct; is echoing col[0]=1 because you are dividing with & see here:
&sort=col[0]=1 & col[1]=0;
An advice; use more names, instead.
You could use
&sort[]=1&sort[]=0;
UPDATE:
To access the last one; you should do, simply;
$_GET['col'][1];
If you want to access, the last number in
$_GET['sort'];
You can do this;
$explode = explode('=',$_GET['sort']);
$end = end($explode);
echo $end; //it will outout 1
If you print your entire query_String, it will print this;
Array
(
[page] => 0
[size] => 50
[filter] => fcol[6]=batteri
[sort] => col[0]=1
[col] => Array
(
[1] => 0
)
)
I'm not sure how the ajaxUrl option is being used, but the output shared in the question doesn't look right.
I really have no idea how the string in the question is showing this format:
&sort=col[0]=1&col[1]=0 (where did sort= come from?)
&filter=fcol[6]=batteri (where did filter= come from?)
If you look at how you can manipulate the ajaxUrl option, you will see this example:
ajaxUrl: "http://mydatabase.com?page={page}&size={size}&{sortList:col}&{filterList:fcol}"
So say you have the following settings:
page = 2
size = 10
sortList is set to [[0,1],[3,0]] (1st column descending sort, 4th column ascending sort)
filters is set as ['','','fred']
The resulting url passed to the server will look like this:
http://mydatabase.com?page=2&size=10&col[0]=1&col[3]=0&fcol[2]=fred
The col part of the {sortList:col} placeholder sets the sorted column name passed to the URL & the fcol part of {filterList:fcol} placeholder sets the filter for the set column. So those are not fixed names.
If the above method for using the ajaxUrl string doesn't suit your needs, you can leave those settings out of the ajaxUrl and instead use the customAjaxUrl option to modify the URL as desired. Here is a simple example (I know this is not a conventional method):
ajaxUrl: "http://mydatabase.com?page={page}&size={size}",
// modify the url after all processing has been applied
customAjaxUrl: function(table, url) {
var config = table.config,
// convert [[0,1],[3,0]] into "0-1-3-0"
sort = [].concat.apply( [], config.sortList ).join('-'),
// convert [ '', '', 'fred' ] into "--fred"
filter = config.lastSearch.join('-');
// send the server the current page
return url += '&sort=' + sort + '&filter=' + filter
}
With the same settings, the resulting URL will now look like this:
http://mydatabase.com?page=2&size=10&sort=0-1-3-0&filter=--fred
This is my own best solution so far, but it's not really elegant:
if (preg_match_all("/[^f]col\[\d+]=\d+/", $_SERVER['QUERY_STRING'], $matches)) {
foreach($matches[0] AS $sortinfo) {
if (preg_match_all("/\d+/", $sortinfo, $matches)) {
if(count($matches[0]) == 2) {
echo "Col: ".$matches[0][0]."<br/>";
echo "Order: ".$matches[0][1]."<br/>";
}
}
}
}
It gives me the info I need
Col: 0
Order: 1
Col: 1
Order: 0
But is clumbsy. Is there a better way?

Making the leap from PhP to Python

I am a fairly comfortable PHP programmer, and have very little Python experience. I am trying to help a buddy with his project, the code is easy enough to write in Php, I have most of it ported over, but need a bit of help completing the translation if possible.
The target is to:
Generate a list of basic objects with uid's
Randomly select a few Items to create a second list keyed to the uid containing new
properties.
Test for intersections between the two lists to alter response accordingly.
The following is a working example of what I am trying to code in Python
<?php
srand(3234);
class Object{ // Basic item description
public $x =null;
public $y =null;
public $name =null;
public $uid =null;
}
class Trace{ // Used to update status or move position
# public $x =null;
# public $y =null;
# public $floor =null;
public $display =null; // Currently all we care about is controlling display
}
##########################################################
$objects = array();
$dirtyItems = array();
#CREATION OF ITEMS########################################
for($i = 0; $i < 10; $i++){
$objects[] = new Object();
$objects[$i]->uid = rand();
$objects[$i]->x = rand(1,30);
$objects[$i]->y = rand(1,30);
$objects[$i]->name = "Item$i";
}
##########################################################
#RANDOM ITEM REMOVAL######################################
foreach( $objects as $item )
if( rand(1,10) <= 2 ){ // Simulate full code with 20% chance to remove an item.
$derp = new Trace();
$derp->display = false;
$dirtyItems[$item->uid] = $derp; //# <- THIS IS WHERE I NEED THE PYTHON HELP
}
##########################################################
display();
function display(){
global $objects, $dirtyItems;
foreach( $objects as $key => $value ){ // Iterate object list
if( #is_null($dirtyItems[$value->uid]) ) // Print description
echo "<br />$value->name is at ($value->x, $value->y) ";
else // or Skip if on second list.
echo "<br />Player took item $value->uid";
}
}
?>
So, really I have most of it sorted I am just having trouble with Python's version of an Associative array, to have a list whose keys match the Unique number of Items in the main list.
The output from the above code should look similar to:
Player took item 27955
Player took item 20718
Player took item 10277
Item3 is at (8, 4)
Item4 is at (11, 13)
Item5 is at (3, 15)
Item6 is at (20, 5)
Item7 is at (24, 25)
Item8 is at (12, 13)
Player took item 30326
My Python skills are still course, but this is roughly the same code block as above.
I've been looking at and trying to use list functions .insert( ) or .setitem( ) but it is not quite working as expected.
This is my current Python code, not yet fully functional
import random
import math
# Begin New Globals
dirtyItems = {} # This is where we store the object info
class SimpleClass: # This is what we store the object info as
pass
# End New Globals
# Existing deffinitions
objects = []
class Object:
def __init__(self,x,y,name,uid):
self.x = x # X and Y positioning
self.y = y #
self.name = name #What will display on a 'look' command.
self.uid = uid
def do_items():
global dirtyItems, objects
for count in xrange(10):
X=random.randrange(1,20)
Y=random.randrange(1,20)
UID = int(math.floor(random.random()*10000))
item = Object(X,Y,'Item'+str(count),UID)
try: #This is the new part, we defined the item, now we see if the player has moved it
if dirtyItems[UID]:
print 'Player took ', UID
except KeyError:
objects.append(item) # Back to existing code after this
pass # Any error generated attempting to access means that the item is untouched by the player.
# place_items( )
random.seed(1234)
do_items()
for key in objects:
print "%s at %s %s." % (key.name, key.x, key.y)
if random.randint(1, 10) <= 1:
print key.name, 'should be missing below'
x = SimpleClass()
x.display = False
dirtyItems[key.uid]=x
print ' '
objects = []
random.seed(1234)
do_items()
for key in objects:
print "%s at %s %s." % (key.name, key.x, key.y)
print 'Done.'
So, sorry for the long post, but I wanted to be through and provide both sets of full code. The PhP works perfectly, and the Python is close. If anyone can point me in the correct direction it would be a huge help.
dirtyItems.insert(key.uid,x) is what i tried to use to make a list work as an Assoc array
Edit: minor correction.
You're declaring dirtyItems as an array instead of a dictionary. In python they're distinct types.
Do dirtyItems = {} instead.
Make a dictionary instead of an array:
import random
import math
dirtyItems = {}
Then you can use like:
dirtyItems[key.uid] = x

Categories