Bizarre Array Mirroring Issue - javascript

I have two arrays, both of which get populated by data from a post request.
The purpose of this is so that when alterations are made to the "live" array, they are compared to the "original" array so changes can be spotted.
Here is my post:
$('#dialogs').load('views/Products/managePicsDialog.php', function(){
var imageArray = [];
var originalImageArray = [];
$('#managePicsDialog').modal();
productId = 1;
$.post(ROOT+'products/fetch-thumbnails', 'pid='+productId, function(data){
imageArray = originalImageArray = data;
nextPriority = imageArray.length+1;
renderImageList(imageArray);
}, 'json')
...
Initially I thought this would be fine, data gets put into imageArray and originalImageArray.
Throughout my code originalImageArray doesn't get touched at all, only imageArray gets manipulated and changed.
Now when it comes to comparing the arrays, it seems originalImageArray copies imageArray on every change which I do not understand why:
function saveChanges(imageArray, originalImageArray)
{
$.each(originalImageArray, function(i, obj){
$.each(obj, function(i2, v){
if(imageArray[i][i2] != v)
{
alert('changed') // Never happens
}
})
})
}
If I "alert each" both arrays the values are clearly shown to copy each other, even though there is no where in my code that states originalImageArray = imageArray except in my $.post method which only gets called once when the dialog is opened.
Can anyone solve this for me?
The contents of the arrays are objects.
Here is the full code to help clarify:
$('#productGrid').on('click', '#managePics', function(e){ // When managepics option is clicked
e.preventDefault(); // Don't go to the hyperlink...
closeMenu(); // Close the popup menu...
$('#dialogs').load('views/Products/managePicsDialog.php', function(){
var imageArray = [];
var originalImageArray = [];
$('#managePicsDialog').modal();
productId = 1;
$.post(ROOT+'products/fetch-thumbnails', 'pid='+productId, function(data){
imageArray = data;
originalImageArray = data.slice(0);
nextPriority = imageArray.length+1;
renderImageList(imageArray);
}, 'json')
$('#fileUpload').fileupload({
url: ROOT+'UploadHandler',
process: [
{
maxFileSize: 2000000000
}
],
progressInterval: 50,
add: function(e, data)
{
data.submit();
},
progressall: function (e, data) {
var progress = parseInt(data.loaded / data.total * 100, 10);
$('#progress .bar').css('width', progress + '%').html(progress+'%');
},
done: function(e, data)
{
n = $.parseJSON(data.result)
pushed = {
"id": "0",
"priority": nextPriority,
"thumb": n.files[0].thumbnail_url,
"deleted": 0
}
imageArray.push(pushed);
renderImageList(imageArray);
}
});
$('#thumbnails').on('click', 'button.delete', function(e){
$(this).closest('.span8').fadeOut('fast', function(){
$(this).detach();
});
idx = $(this).closest('.span8').data('index');
deleteImage(imageArray, idx)
})
$('#managePicsDialog').on('click', '.move-down:not(.disabled)', function(){
idx = $(this).closest('.span8').data('index');
if(imageArray[idx+1])
{
temp = imageArray[idx+1];
imageArray[idx+1] = imageArray[idx];
} else {
temp = imageArray[0];
imageArray[0] = imageArray[idx];
}
imageArray[idx] = temp;
renderImageList(imageArray)
})
$('#managePicsDialog').on('click', '.move-up:not(.disabled)', function(){
idx = $(this).closest('.span8').data('index');
if(imageArray[idx-1])
{
temp = imageArray[idx-1];
imageArray[idx-1] = imageArray[idx];
} else {
temp = imageArray[imageArray.length-1];
imageArray[imageArray.length-1] = imageArray[idx];
}
imageArray[idx] = temp;
renderImageList(imageArray)
})
$('#cancelChanges').click(cancelChanges)
$('#saveChanges').click(function(){
saveChanges(imageArray, originalImageArray)
})
})// Close dialog
})
function saveChanges(imageArray, originalImageArray)
{
// commitChanges(imageArray)
$.each(originalImageArray, function(i, obj){
$.each(obj, function(i2, v){
alert(i2+' => '+v)
})
})
$.each(imageArray, function(i, obj){
$.each(obj, function(i2, v){
alert(i2+' => '+v)
})
})
$.each(originalImageArray, function(i, obj){
$.each(obj, function(i2, v){
if(imageArray[i][i2] != v)
{
alert('changed')
}
})
})
}
function deleteImage(imageArray, index)
{
if(imageArray[index].id == 0) // If is a new image we just remove it from array.
{
imageArray.splice(index, 1);
} else { // If existing image we mark it for deletion.
imageArray[index].deleted = 1;
}
renderImageList(imageArray);
}
function renderImageList(imageArray)
{
var thumbHTML = '';
$.each(imageArray, function(i, v){
if(v.deleted == 0)
{
thumbHTML += '<div class="span8 well" data-index="'+i+'">';
thumbHTML += '<div class="span2">';
thumbHTML += '<img src="images/'+v.thumb+'" height="" width="" class="last-added">';
thumbHTML += '</div>';
thumbHTML += '<div class="span4">';
thumbHTML += '</div>';
thumbHTML += '<div class="span1">';
thumbHTML += '<button class="btn btn-info btn-100 move-up">Move up</button>';
thumbHTML += '<button class="btn btn-info btn-100 move-down">Move down</button>';
thumbHTML += '<button class="btn btn-danger btn-100 delete">Remove</button>';
thumbHTML += '</div>';
thumbHTML += '</div>';
}
})
$('#thumbnails').html(thumbHTML);
}

You need to clone it so they do not share the same reference
imageArray = data;
originalImageArray = data.slice(0);

Related

How to put multiple GET's in an array with jQuery

How do I put multiple GET's in an array?
I want to start with putting all channelId's in an array like this:
var Channels = [ID1, ID2, ID3];
And then a function with $each... But how to do it? :)
Who can help me please? It will be much appreciated
var ItemArray = [];
var d1 = $.get("https://www.googleapis.com/youtube/v3/search?channelId=UCVQ2Z9dNQ2aJJ10f6SgBH0g&type=video&order=date&maxResults=1&part=snippet&KEY",
function (data) {
$.each(data.items, function (i, item) {
idee = item.id.videoId;
tittie = item.snippet.title;
cattit = item.snippet.channelTitle;
datie = item.snippet.publishedAt;
ItemArray.push([datie, cattit, idee, tittie]);
});
});
var d2 = $.get("https://www.googleapis.com/youtube/v3/search?channelId=UC2xskkQVFEpLcGFnNSLQY0A&type=video&order=date&maxResults=1&part=snippet&KEY",
function (data) {
$.each(data.items, function (i, item) {
idee = item.id.videoId;
tittie = item.snippet.title;
cattit = item.snippet.channelTitle;
datie = item.snippet.publishedAt;
ItemArray.push([datie, cattit, idee, tittie]);
});
});
var d3 = $.get("https://www.googleapis.com/youtube/v3/search?channelId=UCGHi_s4RrqUh4hsS4mLbiPg&type=video&order=date&maxResults=1&part=snippet&key=KEY",
function (data) {
$.each(data.items, function (i, item) {
idee = item.id.videoId;
tittie = item.snippet.title;
cattit = item.snippet.channelTitle;
datie = item.snippet.publishedAt;
ItemArray.push([datie, cattit, idee, tittie]);
});
});
$.when(d1, d2, d3).done(function() {
ItemArray.sort(function(a, b) {
return a[0] - b[0];
});
for(i=0;i<=ItemArray.length;i++){
$('#mytable').append('<tr><td>'+ItemArray[i][0]+'</td><td><a target="_blank" href="https://www.youtube.com/user/'+ItemArray[i][1]+'">'+ItemArray[i][1]+'</a></td><td><a target="_blank" href="https://www.youtube.com/watch?v='+ItemArray[i][2]+'">'+ItemArray[i][3]+'</a></td></tr>');
}
})
})
See example below.
The code is commented an should work as expected.
Ask if any questions.
(function($) {
var ItemArray = [];
// List all IDs here
var ids = ["UCVQ2Z9dNQ2aJJ10f6SgBH0g", "UC2xskkQVFEpLcGFnNSLQY0A", "UCGHi_s4RrqUh4hsS4mLbiPg"];
var done = [];
// Go through all ids
$.each(ids, function(index, value) {
// Save all Deferred in variable done
done.push($.get("https://www.googleapis.com/youtube/v3/search?channelId=" + value + "&type=video&order=date&maxResults=1&part=snippet&KEY", fn)); // use function fn for doing all the time the same
});
function fn(data) {
$.each(data.items, function(i, item) {
idee = item.id.videoId;
tittie = item.snippet.title;
cattit = item.snippet.channelTitle;
datie = item.snippet.publishedAt;
ItemArray.push([datie, cattit, idee, tittie]);
});
}
// to use an array as input for when()
// you need th use the prototype method apply to convert it
$.when.apply($, done).done(function() {
// this part stays the same
ItemArray.sort(function(a, b) {
return a[0] - b[0];
});
for (i = 0; i <= ItemArray.length; i++) {
$('#mytable').append('<tr><td>' + ItemArray[i][0] + '</td><td><a target="_blank" href="https://www.youtube.com/user/' + ItemArray[i][1] + '">' + ItemArray[i][1] + '</a></td><td><a target="_blank" href="https://www.youtube.com/watch?v=' + ItemArray[i][2] + '">' + ItemArray[i][3] + '</a></td></tr>');
}
});
})(jQuery);
So loop over the array and make the ajax calls, pushing the Ajax calls into a new array.
var channels = ["a","b","c"],
calls = channels.reduce( function (arr, current) {
var xhr = $.get("http://example.com?q=" + current, function() { /* your code ajax success*/});
arr.push(xhr);
return arr;
}, []);
//Take that array and apply it to the when
$.when.apply($, calls).done( function () {
//Your code
} )

javascript recursive object unordered list keep same index for parent

In this DEMO you can see the red <b> tags are showing a different index from the black ones below, this happens why I am trying to use the same index for both <li> and parents <ul>, but something is not working properly... it seems like, only at the very first step, the index counting in skipped and all the remaining index then is "slipped" one step forward, so they are not matching...
var object = {
sometdhing: {
sometfhing: {
somgething: 'text',
someathing: 'text'
},
someathing: {
somefthing: 'text',
sometghing: 'text'
}
},
someathing: {
somethfing: {
somgething: 'text',
somethihng: 'text'
},
somejthing: {
somethhing: 'text',
somfething: 'text'
}
}
}
var indexes = [];
var object2ul = function (data, level) {
var keys = Object.keys(data);
var json = '<ul>'+ '<b style="color:red">'+level+'</b>';
for (var i=0; i<keys.length; ++i) {
var key = keys[i];
indexes.push(i);
json += '<li>' + "<b>" + indexes.join('_') + "</b> - " + key;
if (typeof(data[key]) === 'object') {
json += object2ul(data[key], indexes.join('_'));
} else {
json += '<ul><li>' + data[key] + "</li></ul>";
}
json += "</li>";
indexes.pop();
}
return json + "</ul>";
}
document.body.innerHTML = object2ul(object, 0);
Please help...
Css did help
Code: http://jsfiddle.net/18obnr9L/3/
here i construct elements from object like ul, li, ol...
var data = {
sometdhing: {
sometfhing: {
somgething: 'atext1',
someathing: 'atext2'
},
someathing: {
somefthing: 'atexta1',
sometghing: 'atexta2'
}
},
someathing: {
somethfing: {
somgething: 'btext1',
somethihng: 'btext2'
},
somejthing: {
somethhing: 'btexta1',
somfething: 'btexta2'
}
}
};
list(data);
function list(data) {
var ul = document.createElement('ol'),
li = document.createElement('li')
main = ul.cloneNode();
getProps(main, data);
document.body.appendChild(main);
function getProps(parent, d) {
for (var i in d) {
if (typeof d[i] == "string") {
addLi(parent, d[i], i);
} else if (d[i] instanceof Object) {
var pli = addLi(parent, '', i);
var temp = ul.cloneNode();
getProps( temp, d[i] )
pli.appendChild(temp);
parent.appendChild(pli);
}
}
}
function createUli(val){
var ul = document.createElement('ul');
var l = li.cloneNode();
ul.appendChild(l);
l.innerText = val;
return ul;
}
function addLi(p, val, i) {
var ele = li.cloneNode();
ele.innerText = i;
if (val != '') ele.appendChild(createUli(val));
p.appendChild(ele);
return ele;
}
}

Array length remains 0 even though I push 'objects' to it

I have a little piece of code that reads some ajax (this bit works) from a server.
var self = this;
var serverItems = new Array();
var playersOnlineElement = $("#playersOnline");
function DataPair(k, v) {
this.key = k;
console.log("new datapair: " + k + ", " + v);
this.value = v;
}
DataPair.prototype.getKey = function() {
return this.key;
}
DataPair.prototype.getValue = function() {
return this.value;
}
$.getJSON("http://127.0.0.1", function(data) {
$.each(data, function(key, val) {
var pair = new DataPair(key, val);
self.serverItems.push(pair);
});
});
console.log(serverItems.length); //Problem is here
for (var i = 0; i < serverItems.length; i = i + 1) {
var dpair = serverItems[i];
if (dpair.getKey() === "playersOnline") {
self.playersOnlineElement.text("Players Online: " + dpair.getValue());
}
}
The datapair and the JSON get loaded but when they are pushed to the array it doesn't seem to work. I tried with self.serverItems and just serverItems because netbeans showed me the scope of the variables being good if I used just serverItems but I am a bit confused as to why this doesn't work. Can anyone help me?
I put in comments where the error is. serverItems.length is 0 even though when debugging in a browser in the DOM tree it has an array serverItems with all the data inside.
Assumingly this serverItems is in another scope and not the one I am calling when I want to get the length?
add this code into the success part, since its asynchronous...
for (var i = 0; i < serverItems.length; i = i + 1) {
var dpair = serverItems[i];
if (dpair.getKey() === "playersOnline") {
self.playersOnlineElement.text("Players Online: " + dpair.getValue());
}
to...
$.getJSON("http://127.0.0.1", function(data) {
$.each(data, function(key, val) {
var pair = new DataPair(key, val);
self.serverItems.push(pair);
for (var i = 0; i < serverItems.length; i = i + 1) {
var dpair = serverItems[i];
if (dpair.getKey() === "playersOnline") {
self.playersOnlineElement.text("Players Online: " + dpair.getValue());
}
});
});

How to count duplicate array elements? (javascript)

I'm trying to make an XML based menu with JavaScript, XML and jQuery. I've been successful at getting the categories of the menu, but haven't been able to generate the items in the categories.
My script is as follows, and later in this thread, I've asked for suggestions for this code:
var animalsXMLurl = 'http://dl.dropboxusercontent.com/u/27854284/Stuff/Online/XML_animals.xml';
$(function() {
$.ajax({
url: animalsXMLurl, // name of file you want to parse
dataType: "xml",
success: function parse(xmlResponse) {
var data = $("item", xmlResponse).map(function() {
return {
id: $("animal_id", this).text(),
title: $("animal_title", this).text(),
url: $("animal_url", this).text(),
category: $("animal_category", this).text().split('/'),
};
}).get();
var first_item = category_gen(data, 0);
$('ul.w-nav-list.level_2').append(first_item);
var categnumber = new Array();
for (i = 1; i <= data.length; i++) //for splitting id, and getting 0 for category_number (1 or 2 or 3...and so on)
{
categnumber[i] = data[i].id.split('_');
console.log(categnumber[i][0]);
for (j = 1; j <= data.length; j++) //appending via a function.
{
var data_text = category_or_animal(data, categnumber, j);
console.log(data_text);
$('ul.w-nav-list.level_2').append(data_text);
}
}
function category_or_animal(d, catg, k) {
var catg1 = new Array();
var catg2 = new Array();
var catg1 = d[k].id.split('_');
if (d[k - 1]) {
var catg2 = d[k - 1].id.split('_');
//if(d[k-1].id)
if (catg1[0] != catg2[0])
return category_gen(d, k);
} else
return '</ul>' + animal_gen(d, k);
}
function category_gen(d, z) {
var category_var = '<li class="w-nav-item level_2 has_sublevel"><a class="w-nav-anchor level_2" href="javascript:void(0);"><span class="w-nav-title">' + d[z].category + '</span><span class="w-nav-arrow"></span></a><ul class="w-nav-list level_3">';
return category_var;
}
function animal_gen(d, z) {
var animal_var = '<li class="w-nav-item level_3"><a class="w-nav-anchor level_3" href="animals/' + d[z].url + '"><span class="w-nav-title">' + d[z].title + '</span><span class="w-nav-arrow"></span></a></li>';
return animal_var;
}
}, error: function() {
console.log('Error: Animals info xml could not be loaded.');
}
});
});
Here's the JSFiddle link for the above code: http://jsfiddle.net/mohitk117/d7XmQ/4/
In the above code I need some alterations, with which I think the code might work, so I'm asking for suggestions:
Here's the function that's calling separate functions with arguments to generate the menu in above code:
function category_or_animal(d, catg, k) {
var catg1 = new Array();
var catg2 = new Array();
var catg1 = d[k].id.split('_');
if (d[k - 1]) {
var catg2 = d[k - 1].id.split('_');
//if(d[k-1].id)
if (catg1[0] != catg2[0])
return category_gen(d, k);
} else
return animal_gen(d, k) + '</ul>';
}
At the if(catg1[0] != catg2[0]) it checks if the split string 1_2 or 1_3 is equal to 1_1 or 1_2 respectively. By split, I mean the first element: 1 .... if you have a look at the xml: [ :: Animals XML :: ], you'll see that the animal_id is in the format of %category_number% _ %item_number% ... So I need to create the menu with CATEGORY > ITEM (item=animal name)
Now if I could return category_gen() + animal() with animal(){ in a for loop for all the matching category id numbers} then maybe this could be complete! But I don't of a count script for conditioning the for loop (i=0;i<=count();i++)...
Would anyone know of how to get this script functioning?
Hard to tell what the provided JSFiddle is trying to do.
This is my best stab at it. I used JQuery to parse the XML out into categories and generate lists of items.
http://jsfiddle.net/d7XmQ/8/
"use strict";
var animalsXMLurl = 'http://dl.dropboxusercontent.com/u/27854284/Stuff/Online/XML_animals.xml';
$(function () {
var $menu = $('#menu');
$.ajax({
url: animalsXMLurl, // name of file you want to parse
dataType: "xml",
success: handleResponse,
error: function () {
console.log('Error: Animals info xml could not be loaded.');
}
});
function handleResponse(xmlResponse) {
var $data = parseResponse(xmlResponse);
createMenu($data);
}
function parseResponse(xmlResponse) {
return $("item", xmlResponse).map(function () {
var $this = $(this);
return {
id: $this.find("animal_id").text(),
title: $this.find("animal_title").text(),
url: $this.find("animal_url").text(),
category: $this.find("animal_category").text()
};
});
}
function createMenu($data) {
var categories = {};
$data.each(function (i, dataItem) {
if (typeof categories[dataItem.category] === 'undefined') {
categories[dataItem.category] = [];
}
categories[dataItem.category].push(dataItem);
});
$.each(categories, function (category, categoryItems) {
var categoryItems = categories[category];
$menu.append($('<h2>').text(category));
$menu.append(createList(categoryItems));
});
}
function createList(categoryItems) {
var $list = $('<ul>');
$.each(categoryItems, function (i, dataItem) {
$list.append(createItem(dataItem));
});
return $list;
}
function createItem(dataItem) {
return $('<li>').text(dataItem.title);
}
});
You can solve this without using any for/while loop or forEach.
function myCounter(inputWords) {
return inputWords.reduce( (countWords, word) => {
countWords[word] = ++countWords[word] || 1;
return countWords;
}, {});
}
Hope it helps you!

Autocomplete with javascript, not passing the variables

I'm using this autocomplete code to be able to pull stock information:
var YAHOO = {};
YAHOO.util = {};
YAHOO.util.ScriptNodeDataSource = {};
var stockSymbol;
var compName;
YUI({
filter: "raw"
}).use("datasource", "autocomplete", "highlight", function (Y) {
var oDS, acNode = Y.one("#ac-input");
oDS = new Y.DataSource.Get({
source: "http://d.yimg.com/aq/autoc?query=",
generateRequestCallback: function (id) {
YAHOO.util.ScriptNodeDataSource.callbacks =
YUI.Env.DataSource.callbacks[id];
return "&callback=YAHOO.util.ScriptNodeDataSource.callbacks";
}
});
oDS.plug(Y.Plugin.DataSourceJSONSchema, {
schema: {
resultListLocator: "ResultSet.Result",
resultFields: ["symbol", "name", "exch", "type", "exchDisp"]
}
});
acNode.plug(Y.Plugin.AutoComplete, {
maxResults: 10,
resultTextLocator: "symbol",
resultFormatter: function (query, results) {
return Y.Array.map(results, function (result) {
var asset = result.raw,
text = asset.symbol +
" " + asset.name +
" (" + asset.type +
" - " + asset.exchDisp + ")";
return Y.Highlight.all(text, query);
});
},
requestTemplate: "{query}&region=US&lang=en-US",
source: oDS
});
acNode.ac.on("select", function (e) {
alert(e.result.raw.name);
stockSymbol = e.result.raw.symbol;
compName = e.result.raw.name;
alert("stockSymbol is "+stockSymbol);
alert("compName is "+compName);
});
});
I have a text field where the text is being entered, then I need to display a few pieces of information based on what was entered:
$(document).ready(function(e) {
//$(".selector").button({icons: {primary: "ui-icon-search"}});
//$(".home").button({icons: {primary: "ui-icon-home"}});
var q = window.location.href.split("?ac-input=");
alert("q is "+q)
if (q && q[1])
$("input").val(q[1]);
alert("what is this?" +q[1]);
runForm();
});
..........
function runForm(){
$("#stock_news").html("");
//var stockSymbol = e.result.raw.symbol;
alert('stockSymbol in runForm is ' +stockSymbol);
alert('compname is runForm is '+compName);
var newsStocks = "http://query.yahooapis.com/v1/public/yql?.......";
$.getJSON(newsStocks, function(data) {
var headlines = data.query.results.a;
newStr = "<h3>Current Headlines</h3>";
newStr += "<ol>";
for(var i=0; i<headlines.length; ++i){
var news = headlines[i];
newStr += "<li><a href='"+news.href+"'>"+news.content+"</a></li>";
}
newStr += "</ol>";
$("#stock_news").html(newStr);
});
htmlStr = '<img src="http://chart.finance.yahoo.com/z?s='+stockSymbol+'&t=5d&q=l&l=off&z=s&region=US&lang=en-EN"/>';
$("#stock_graph").html(htmlStr);
}
What is happening is, the stockSymbol and compName are correctly set from entering, but for some reason nothing renders on the page, as q is undefined....Any ideas on where I am messing up here?
Figured it out. I needed to call runForm inside the acNode.ac.on("select", function (e)

Categories

Resources