I have taken a few different approaches at solving this problem, but have never really been happy with the inflexibility of my solutions. I am trying to map an object created in javascript to a container in my html document.
Let me give you an example. Say I have a Phone Number object in javascript:
var PhoneNumber = function(number, type) {
this.number = number;
this.type = type;
}
var myPhone = new PhoneNumber('5555555555', 'Home');
And within my html document, I have a series of DIV's which are basically empty containers waiting to be populated by the forementioned object and displayed to the user.
<div id="phoneNumberContainer">
<div class="row">
<div id="number"></div>
<div id="type"></div>
</div>
</div>
Now, I want to have a function within my javascript that will automatically take that phone number object and fill the phoneNumberContainer elements with its data. I have multiple types of objects with different parameters so it has to be generic.
Currently I find myself doing a lot of this:
function mapPhoneNumber() {
var numberContainer = document.getElementById('number');
numberContainer.innerHTML = myPhone.number;
var typeContainer = document.getElementById('type');
typeContainer.innerHTML = myPhone.type;
}
Which of course works just fine, but its calls for writing a lot of the same code over and over again for every single object I want to map. I wish there was a way to do it like this so I could just pass the object and container into a function and it automatically populate the DIV elements based on the object:
function mapPhoneNumber(phoneObject) {
var phoneContainerChildren = document.getElementById('phoneNumberContainer').childNodes;
for(x in phoneContainerChildren) {
phoneContainerChildren[x] = myPhone.number;
}
}
Of course this is not a working example as the order of the containers are not guaranteed to be the same as the phone number objects, and the children will have other types of nodes beside my divs etc etc. I could put the phone number parameter name in the actual ID of the DIV element and then match it against the object and fill the object when I have a match, but I hate to have to have such specific ID's on my DIV elements that if changed by another designer will completely destroy my javascript.
Does anyone have any suggestions on how I might implement something like this? I am not against jQuery as I do use a lot of it in my solutions.
I'm not 100 % sure if it's what you're looking for but I think this might be a possible solution:
var DOMable = {
writeToDOM : function( node ){
for( var i in this ) if( this.hasOwnProperty( i ) ){
node.find( "." + i ).text( this[i] );
}
}
};
var PhoneNumber = function(number, type) {
this.number = number;
this.type = type;
};
PhoneNumber.prototype = DOMable;
var myPhone = new PhoneNumber('5555555555', 'Home');
Then you can call:
myPhone.writeToDOM( jQuery( '#myPhone' ) );
for a HTML structure like:
<div id="myPhone">
<div class="number">
</div>
<div class="type">
</div>
</div>
I use something similar to this in many of my projects.
<div id="container">
<div class="row">
<div class="prop"></div>
<div class="propValue"></div>
</div>
</div>
function BindValues(container, prop, propValue)
{
container.find(".prop").val = prop;
container.find(".propValue").val = propValue;
return container;
}
You can add a method to your phone number object and use classes in your HTML instead of IDs so you can have more than one per page. Then, all your code is attached to the object and you don't have to retype it everytime you want it:
<div id="homePhone" class="phoneNumberContainer">
<div class="row">
<div class="number"></div>
<div class="type"></div>
</div>
</div>
var PhoneNumber = function(number, type) {
this.number = number;
this.type = type;
}
PhoneNumber.prototype.setHTML(dest) {
var item = $(dest);
item.find(".type").html(this.type);
item.find(".number").html(this.number);
}
var myPhone = new PhoneNumber('5555555555', 'Home');
myPhone.setHTML("#homePhone");
To do this any more automatically would require us knowing more about how phone numbers are created, how the HTML is created and how one can be automatically associated with the other? Do you have a list of PhoneNumber objects that you just want to create a bunch of corresponding HTML? Or does the HTML already exist and you want to fill it?
Related
I've looked over numerous Stack Overflow discussions on getElementsByClassName but can't seem to find anything that can help me resolve this particular issue. To explain . . .
I have the following javascript
field_to_update.innerHTML = '';
var elOptNew = document.createElement('option');
elOptNew.text = '---'
elOptNew.value = '';
field_to_update.add(elOptNew);
field_to_update.options[0].selected = true;
var track_names = document.getElementsByClassName('wpaudio');
for (i=0; i<track_names.length; i++) {
var track_name = track_names[i].innerHTML;
var elOptNew = document.createElement('option');
elOptNew.text = track_name.replace("&", "&");
elOptNew.value = track_name;
field_to_update.add(elOptNew); // standards compliant; doesn't work in IE
}
and I am looking to extract the names of a list of audio files using the line var track_names = document.getElementsByClassName('wpaudio') which refers to the following code included in the functions.php file of a wordpress child theme.
<ol id="audioFilesList" class="reactionFormAudio">
<?php
// loop through rows (parent repeater)
while( have_rows('song_upload') ): the_row(); ?>
<li><p class="wpaudio" name="audioFileName"><?php the_sub_field('track_name'); ?></p><br>
The above scenario works fine. BUT i have decided to not use the ordered list of audio files as listed above - but instead us the default audio playlist that can be created within a wordpress post, which produces the following code:
<div class="wp-playlist-tracks">
<div class="wp-playlist-item wp-playlist-playing">
<a class="wp-playlist-caption" href="https://www.futureproofpromotions.com/wp-content/uploads/2020/09/01_WhereToBegin-128.mp3">
1.
<span class="wp-playlist-item-title">
“Where To Begin” </span>
<span class="wp-playlist-item-artist"> — Alice Clayton</span>
</a>
<div class="wp-playlist-item-length">2:57</div>
</div>
<div class="wp-playlist-item">
<a class="wp-playlist-caption" href="https://www.futureproofpromotions.com/wp-content/uploads/2020/09/02_BeingAlone-128.mp3">
2.
<span class="wp-playlist-item-title">
“Being Alone” </span>
<span class="wp-playlist-item-artist"> — Brosnan</span>
</a>
<div class="wp-playlist-item-length">3:15</div>
</div>
</div>
</div>
However, when I swap the javascript line from document.getElementsByClassName('wpaudio'); to document.getElementsByClassName('wp-playlist-caption'); in order to reference the different class name in the the new html, it doesn't display any names!
I am very new indeed to javascript so this may be obvious to someone skilled in that language, but I do have a limited knowlege of php.
Would anybody be able to explain why when i change the class name/reference in the above scenario I get no names displayed?
FYI I have also tried changing document.getElementsByClassName() to document.querySelectorAll() which also works well, when referencing the original class ('.wpaudio') - but again produces no result when referencing ('.wp-playlist-caption') or any other class name nested within it (such as .wp-playlist-item-title or .wp-playlist-item-artist).
Any help with the above would be most appreciated
Since wp-playlist-caption has multiple nested elements, you can either query for each one of them and string them together or take the lazy route and use .innerText. That will extract the rendered plaintext inside the element and its children.
// Wait until the page has loaded
document.addEventListener('DOMContentLoaded', () => {
var field_to_update = document.getElementById('reactionForm_strongestTrack');
field_to_update.innerHTML = '';
var elOptNew = document.createElement('option');
elOptNew.text = '---'
elOptNew.value = '';
field_to_update.add(elOptNew);
field_to_update.options[0].selected = true;
// Search for all playlist-captions inside the playlist-tracks list.
// 'Currently playing' has a playlist-caption too,
// limiting to the tracklist excludes it
document.querySelectorAll('.wp-playlist-tracks .wp-playlist-caption')
.forEach( // The following arrow function will be called for each element
track => {
// There are nested elements but we just want the plaintext
let track_name = track.innerText;
// Create a new element and append to the select as before
let elOptNew = document.createElement('option');
elOptNew.text = track_name.replace("&", "&");
elOptNew.value = track_name;
field_to_update.add(elOptNew);
});
});
Additional reference for arrow functions.
EDIT: I changed the var to class but I might have some error in here.
Here it goes, I want to have this paragraph in which the user can change the name on the following paragraph. The code I'm using only changes one name but the rest remains the same.
<script type="text/javascript">
function changey(){
var userInput = document.getElementById('userInput').value;
var list = document.getElementByClassName('kiddo');
for (let item of list) {
item.innerHTML = userInput;
}
}
</script>
<input id="userInput" type="text" value="Name of kid" />
<input onclick="changey()" type="button" value="Change Name" /><br>
Welcome to the site <b class="kiddo">dude</b> This is how you create a document that changes the name of the <b class="kiddo">dude</b>. If you want to say <b class="kiddo">dude</b> more times, you can!
No error messages, the code only changes one name instead of all three.
Use class="kiddo" instead of id in the html.
You can then use var kiddos = document.getElementsByClassName('kiddo') which will return an array of all the elements of that class name stored in kiddos.
Then you just need to loop through the values and change what you want.
Example of loop below:
for (var i = 0; i < kiddos.length; i++) {
kiddos[i].innerHTML = userInput;
}
id should be unique on the page. Javascript assumes that there is only one element with any given id. Instead, you should use a class. Then you can use getElementsByClassName() which returns an entire array of elements that you can iterate over and change. See Select ALL getElementsByClassName on a page without specifying [0] etc for an example.
Hello You should not use id, instead use class.
Welcome to the site <b class="kiddo">dude</b> This is how you create a document that changes the name of the <b class="kiddo">dude</b>. If you want to say <b class="kiddo">dude</b> more times, you can!
After That on Js part :
<script type="text/javascript">
function changey(){
var userInput = document.getElementById('userInput').value;
var list = document.getElementByClassName('kiddo');
for (let item of list) {
item.innerHTML = userInput;
}
}
</script>
you should use class instated of id. if you use id then the id [kiddo] must be unique
In short, document.querySelectorAll('.kiddo') OR
document.getElementsByClassName('kiddo') will get you a list of elements to loop through. Take note of querySelectorAll, though - it uses a CSS selector (note the dot) and doesn't technically return an array (you can still loop through it, though).
See the code below for some full working examples (const and arrow functions are similar to var and function, so I'll put up a version using old JavaScript, too):
const formEl = document.querySelector('.js-name-change-form')
const getNameEls = () => document.querySelectorAll('.js-name')
const useNameFromForm = (formEl) => {
const formData = new FormData(formEl)
const nameValue = formData.get('name')
const nameEls = getNameEls()
// Set the text of each name element
// NOTE: use .textContent instead of .innerHTML - it doesn't get parsed, so it's faster and less work
nameEls.forEach(el => el.textContent = nameValue)
}
// Handle form submit
formEl.addEventListener('submit', (e) => {
useNameFromForm(e.target)
e.preventDefault() // Prevent the default HTTP request
})
// Run at the start, too
useNameFromForm(formEl)
.name {
font-weight: bold;
}
<!-- Using a <form> + <button> (submit) here instead -->
<form class="js-name-change-form">
<input name="name" value="dude" placeholder="Name of kid" />
<button>Change Name</button>
<form>
<!-- NOTE: Updated to use js- for js hooks -->
<!-- NOTE: Changed kiddo/js-name to spans + name class to remove design details from the HTML -->
<p>
Welcome to the site, <span class="js-name name"></span>! This is how you create a document that changes the name of the <span class="js-name name"></span>. If you want to say <span class="js-name name"></span> more times, you can!
</p>
var formEl = document.querySelector('.js-name-change-form');
var getNameEls = function getNameEls() {
return document.querySelectorAll('.js-name');
};
var useNameFromForm = function useNameFromForm(formEl) {
var formData = new FormData(formEl);
var nameValue = formData.get('name');
var nameEls = getNameEls(); // Set the text of each name element
// NOTE: use .textContent instead of .innerHTML - it doesn't get parsed, so it's faster and less work
nameEls.forEach(function (el) {
return el.textContent = nameValue;
});
};
// Handle form submit
formEl.addEventListener('submit', function (e) {
useNameFromForm(e.target);
e.preventDefault(); // Prevent the default HTTP request
});
// Run at the start, too
useNameFromForm(formEl);
<button class="js-get-quote-btn">Get Quote</button>
<div class="js-selected-quote"><!-- Initially Empty --></div>
<!-- Template to clone -->
<template class="js-quote-template">
<div class="js-quote-root quote">
<h2 class="js-quote"></h2>
<h3 class="js-author"></h3>
</div>
</template>
You have done almost everything right except you caught only first tag with class="kiddo".Looking at your question, as you need to update all the values inside tags which have class="kiddo" you need to catch all those tags which have class="kiddo" using document.getElementsByClassName("kiddo") and looping over the list while setting the innerHTML of each loop element to the userInput.
See this link for examples:https://www.w3schools.com/jsref/met_document_getelementsbyclassname.asp
try:
document.querySelectorAll('.kiddo')
with
<b class="kiddo">dude</b>
So basically every time I click on the icon '.favorite i' it should add an object to my array. If I click the first time it adds the parent div to the array, but on the second time it deletes the first one and grabs the last parent div.
I'm working with three tabs called 'Monday', 'Tuesday' and 'Favorites'. I have a toggle icon which is an empty heart at start 'favorite i'. If I'm in Monday and click on the icon, the empty heart turns to be filled out and its parent is cloned and added to the '#fav' tab. When this happens the clone is saved to local storage. So if people refresh the page, they can still see their preferences.
When the heart is clicked in one of those cloned divs that specific div is removed from '#fav' and will also have to be removed from the array and local storage too.
To conclude, I need to save each cloned div into an array/local storage and then be able to delete each one of those from the array when these are removed from the #fav tab.
How to overcome this issue? Many thanks.
HTML
<div class="container">
<div class="tabs_main">
<div class="col-md-5"><a data-target="#mon" class="btn active" data-toggle="tab">Monday</a></div>
<div class="col-md-5"><a data-target="#tue" class="btn active" data-toggle="tab">Tuesday</a></div>
<div class="col-md-2"><a data-target="#fav" class="btn active" data-toggle="tab"><i class="fa fa-heart" aria-hidden="true"></i></a></div>
</div>
<div class="tab-content">
<div class="tab-pane active" id="mon">
<br>
<div class="spaces">
<div class="box-container">
<div class="box not-selected" id="box1">
<i class="fa fa-heart-o" aria-hidden="true"></i>
</div>
<div class="box-container">
<div class="box not-selected" id="box2">
<i class="fa fa-heart-o" aria-hidden="true"></i>
</div>
</div>
</div>
<div class="tab-pane" id="tue">
<br>
<div class="spaces">
</div>
</div>
<div class="tab-pane" id="fav">
<br>
</div>
</div>
</div>
JS
$('div.tab-pane').on('click', '.favorite', function(e) {
var add = $(this).parent().parent();
add.each(function(){
if ($(add.find('.not-selected .favorite i').hasClass('fa-heart'))) {
var boxContent = $(add).clone(true, true);
var showHide = $(boxContent).find(".session").addClass('selected').removeClass('not-selected');
var get = $(boxContent).wrap('<p/>').parent().html();
$(boxContent).unwrap();
var tempArray = [];
tempArray.push(get);
var myJSONString = JSON.stringify(get);
var parseString = $.parseJSON(myJSONString);
var finalString = myJSONString.replace(/\r?\\n/g, '').replace(/\\/g, '').replace(/^\[(.+)\]$/,'$1').replace (/(^")|("$)/g, '');
var final = localStorage.setItem('sessions', finalString);
$("#fav").append(tempArray);
};
});
});
Fiddle: https://jsfiddle.net/itsfranhere/nbLLc3L0/44/
Your question title is quite clear...
But your question itself and the code you provide prevents anyone to answer with full assurance.
Here is what the provided code produces, as an attempt to reproduce.
Now if I do not bother that code, which I think no one can deduct what it should do exactly...
Your question in title can be can answered by:
Simple! You declare (using var) the tempArray at every click.
That is why it do not retain the information (whatever it is supposed to retain) of the previous click.
I'm not "satisfied" of this answer to you... So if this do not answers completely your issue, please edit your question with more details. Feel free to fork the CodePen to make it look more like your project.
EDIT
From what I get of your script, you want to save "favorited" divs to localstorage. This implies you also have to remove them from localstorage and favorites tab if one is "unfavorited".
Also, you use id on "to be cloned" element. Be extremely cautious with this. An id has to be unique. So if the id is usefull (which was not obvious in the provided code), ensure you make it unique when you clone the element.
I improved you attempt to remove spaces and line feeds in what is to be saved.
Another good advise I have to give you is to use significative variable names in your code. Make your code speak by itself. Readability helps!
Here is your code, updated to do what is mentionned above. Have a close look to comments in code.
var tempArray = [];
// Clones
$('div.tab-pane').on('click', '.favorite', function(e) {
e.preventDefault();
// Elements we play with... Having significative variable names.
var heartLink = $(this);
var box = heartLink.parent('.box');
var container = box.parent('.box-container');
var favoriteTab = $("#fav .spaces");
// I don't know what is the use for those 3 lines below.
var idFind = box.attr("id");
var idComplete = ('#' + idFind);
console.log(idComplete);
//TOGGLE FONT AWESOME ON CLICK
heartLink.find('i').toggleClass('fa-heart fa-heart-o'); // .selected or not, you need those 2 classes to toggle.
box.toggleClass("selected not-selected"); // Toggle selected and not-selected classes
// Clone div
var boxContent = container.clone(true, true);
// Change the id
var thisID = boxContent.attr("id")+"_cloned";
boxContent.attr("id", thisID);
// Get the html to be saved in localstorage
var get = boxContent.wrap('<p>').parent().html();
get = get.replace(/\r?\n/g, "").replace(/>\s*</g, "><"); // remove line feeds and spaces
console.log(get);
boxContent.unwrap();
// Decide to add or remove
if(box.hasClass("selected")){
console.log("Add to array")
tempArray.push(get);
// Add to favorites tab
favoriteTab.append(boxContent);
}else{
console.log("Remove from array");
var index = tempArray.indexOf(get);
tempArray.splice(index);
// Remove from favorite tab
favoriteTab.find("#"+thisID).remove();
}
// Save
localStorage.setItem('sessions', tempArray.join(""));
});
// Append item if localstorage is detected
if (localStorage["sessions"]) {
$("#fav .spaces").append(localStorage["sessions"]);
console.log( localStorage.getItem('sessions') );
}
Updated CodePen
Don't save div elements in localStorage. I recommend you use an object constructor function like below to create a unique object for each [whatever] pushing these into an array then to localStorage in a try block.
localStorage.setItem('myobjects', JSON.stringify(myobjects));
// Object Constructor Functions
function Myobject(id, username, password) {
this.id = id;
this.username = username;
this.password = password;
this.type = 'credential';
}
function duplicate(id,obj){
var result = false;
obj.forEach( function (arrayItem){
if (arrayItem.id == id){
result = true;
}
});
return result;
}
function deleteObject(type, id){
var obj = {};
if (type === 'foo') {
obj = myobjectwhatever;
deleteThis(obj);
//save to local storage
try {
localStorage.setItem('myobject', JSON.stringify(myobjects));
}
catch (e) {
console.log(e);
}
}
else if (type === 'bar') {
//...
}
function deleteThis(o){
try {
for (var i = 0, iLen = o.length; i < iLen; i++) {
if (o[i].id === id) {
o.splice(i, 1);
}
}
}
catch (e) {
console.log(e);
}
}
}
I'm a beginner in JavaScript, and i'm writing a simple To-do list application. That accepts user input and adds it as a task in a form of a checkbox.
The problem is that, the code has become more and more repetitive, I tried to make functions for the most repeating parts. But i feel that there's a better way to do that using some kind of DOM native functions.
Here's my code (i'm writing a comment where i feel that there're better choice to make):
window.onload = function(){
submitBtn.addEventListener("click", function(){
//Some code ...
var task = document.createElement("input");
task.id = "task" + i;
task.type = "checkbox";
var taskLabel = document.createElement("label");
taskLabel.htmlFor = "task" + i;
taskLabel.appendChild(document.createTextNode(textBox.value));
//This is from a function i've created to create buttons
var deleteBtn = createButton("delete");
var undoBtn = createButton("undo", "none");
var divideBtn = createButton("divide");
var taskContainer = document.createElement("p");
//A LOT of appendChild is happening .. How can i minimize that using
//native DOM methods
taskContainer.appendChild(task);
taskContainer.appendChild(taskLabel);
taskContainer.appendChild(deleteBtn);
taskContainer.appendChild(divideBtn);
taskContainer.appendChild(undoBtn);
taskPool.appendChild(taskContainer);
//the rest of the code ....
});
}
This is the reason most people use jQuery and template systems like Handlebars or Mustache. It's actually a lot faster, not to mention cleaner to implement and thus easier to maintain, to simply insert your complete view block into the DOM instead of manually creating the individual DOM elements and appending them one by one.
The recommended way to manipulate the DOM using jQuery is to do something like:
var taskName = 'task'+i,
taskLabel = textBox.value,
taskHtml =
'<div>
<input type="checkbox" name="'+taskName+'">
<label for="'+taskNAme+'">'+taskLabel+'</label>
<fieldset>
<button id="btnDel'+i+'">Delete</button>
<button id="btnDiv'+i+'">Divide</button>
<button id="btnUndo'+i+'">Undo</button>
</fieldset>
</div>';
$(taskHtml).appendTo('#TaskPool');
Creating large DOM constructs in a single go through innerHTML is a lot faster than manually creating and appending the individual elements.
However, this still requires mixing HTML and JS, which is pretty ugly. So that's why these days developers opt for templates, which allow you to do something like:
<script id="task-template" type="text/x-handlebars-template">
<div>
<input type="checkbox" name="task{{i}}">
<label for="task{{i}}">{{label}}</label>
<fieldset>
<button id="btnDel{{i}}">Delete</button>
<button id="btnDiv{{i}}">Divide</button>
<button id="btnUndo{{i}}">Undo</button>
</fieldset>
</div>
</script>
Then in your click handler:
var source = $("#task-template").html(),
template = Handlebars.compile(source),
context = {
i: i,
label: textBox.value
},
html = template(context);
$('#TaskPool').append(html);
And from there, you can take it one step further and add two-way data binding, such as through Angular.js, Kockout.js or jsViews (+ jsRender). Then you just have something like this:
<ol id="TasksList">
<li ng-repeat="task in tasks | orderBy:orderProp">
<input type="checkbox" name="{{task.name}}" ng:model="task.checked">
<label for="{{task.name}}">{{task.label}}</label>
<fieldset>
<button ng-click="deleteTask(task.id)">Delete</button>
<button ng-click="divideTask(task.id)">Divide</button>
<button ng-click="undoTask(task.id)">Undo</button>
</fieldset>
</li>
</ol>
And in your controller:
$scope.orderProp = 'id';
$scope.nextId = 0;
$scope.addTask = function(label) {
var id = $scope.nextId++,
task = {
id: id,
label: label,
name: 'task'+id,
checked: false
};
$scope.tasks.push(task);
};
$scope.deleteTask = function(id) { ... };
$scope.divideTask = function(id) { ... };
$scope.undoTask = function(id) { ... };
If you want to minimize your code wherever you can then using a library like jquery would be one of your best options.
However, if in this case you'd prefer to stick to 'pure' javascript, you could avoid all the appends up there, by adding a method to the Node object of the DOM similar to this one:
/* is Node.prototype.multiAppend already defined? */
if( typeof Node.prototype.multiAppend !== "function" ) {
Node.prototype.multiAppend = (function() {
/*get the Array.prototype.slice method to use on the returned function*/
var slice = [].slice;
/*the function multiAppend comes to be*/
return function() {
var i = 0,
max = arguments.length;
for (; i < max; i++) {
this.appendChild(arguments[i]);
}
/*allow chainability*/
return this;
};
})();
}
This would allow you to do something like this:
var item = document.getElementsByClassName('item')[0],
/*create elements*/
h1 = document.createElement("h1"),
div = document.createElement("div"),
p = document.createElement("p");
/*append them to item with just one line*/
item.multiAppend(h1, div, p);
Take a look at the demo here: http://jsfiddle.net/8mjBR/2/ *
I have hundreds, maybe thousands of charts for stores. The only difference is the name of the store and the product. The HTML code is dynamically generated once/day. Even minified, it takes forever to load (at least it feels like an eternity). If I use Firebug, then loading the file does take a very, very long time to load.
The stores and products are created from a table that's generated each morning. Since each table has a title (e.g., "JohnsMarket"), the ids cannot be reduced to numbers (e.g., 'store1', 'store2').
All of the other SO solutions to repetitive code use numbered ids.
For each store/product, I have to repeat the following 3 snippets.
<div id="JohnsMarket_Soup" class="frmStep">
<div id="JohnsMarket_soup_chart" ></div>
<div class="layout">
<div class="layout_slider-settings">
<div class="loading" id="JohnsMarket_soup_loading"></div>
</div>
<div class="layout_slider"><input id="JohnsMarket_soup_slider" name="area" value="1" ></div>
<div class="layout_slider-settings"> </div>
</div>
</div>
if ( ui.panel.id==='JohnsMarket' )
{
if( typeof JohnsMarket_soup_chart_data === 'undefined' )
{
$('.loading_graph_msg').show();
window.setTimeout(function() { JohnsMarket_soup_data=checkData( JohnsMarket_soup_data,'JohnsMarket' );
JohnsMarket_soup_chart_data = createChart(JohnsMarket_soup_data, 'JohnsMarket_soup_chart', 'JohnsMarket Soup', 50, 7, -1); },50 );
$('.loading_graph_msg').hide('fast');
}
}
});
jQuery('#JohnsMarket_soup_slider').slider({}
$('#JohnsMarket_soup_loading').show();
var x = this.getValue();
window.setTimeout(function() {
JohnsMarket_soup_chart_data.replot();
JohnsMarket_soup_chart_data.destroy();
JohnsMarket_soup_chart_data = createChart(JohnsMarket_soup_data, 'JohnsMarket_soup_chart_data', 'JohnsMarket Soup', 5, x*7, -1);
},20 );
}
});
I can't say I fully understand what your whole problem statement looks like, but you can drastically compress all your code into one function that is used over and over again. This will, at least trim the size of the code down. Since you only showed one example of the data, I can't be sure what exactly is common from one data set to the next, but I made an assumption in order to show you how it can all be procedurized. You could collapse all the code to this:
function checkItem(idStr) {
if ( ui.panel.id == idStr) {
// generate derived names
var soupChartDataName = idStr + "_soup_chart_data";
var soupDataName = idStr + "_soup_data";
var soupChartData = idStr + "_soup_chart_data";
var soupChart = idStr + "_soup_chart";
var soup = idStr + " Soup";
var soupSlider = idStr + "_soup_slider";
var soupLoading = idStr + "_soup_loading";
if (typeof window[soupChartDataName] === 'undefined') {
$('.loading_graph_msg').show();
window.setTimeout(function() {
window[soupDataName] = checkData(window[soupDataName], idStr );
window[soupChartData] = createChart(window[soupChartData], soupChart, soup, 50, 7, -1);
}, 50);
$('.loading_graph_msg').hide('fast');
}
$("#" + soupSlider).slider({});
$("#" + soupLoading).show();
var x = this.getValue();
window.setTimeout(function() {
window[soupChartDataName].replot();
window[soupChartDataName].destroy();
window[soupChartDataName] = createChart(soupDataName, soupChartData, soup, 5, x*7, -1);
}, 20);
}
}
checkItem("JohnsMarket");
Then, for all the other items just call checkItem() with a different idString and no additional code. If I didn't guess the commonality among them quite correctly, you should be able to get the idea for how you can generate all the names being used from one or two common roots. For example, if "soup" isn't common among all the derived names, then maybe you need to pas that root into checkItem too so it can vary from one name to the next. If this were my code, I wouldn't be using so many global variables and I'd hang them off some object in my page, but that's your choice.
Note - for global variables, we access them off the windowobject so we can use the derived variable names as indexes.
And, you could create the HTML from a string template like this:
function createItem(idStr) {
var template = '<div id="xxxx_soup_chart" ></div><div class="layout"><div class="layout_slider-settings"><div class="loading" id="xxxx_soup_loading"></div></div><div class="layout_slider"><input id="xxxx_soup_slider" name="area" value="1" ></div><div class="layout_slider-settings"> </div></div>';
var o = document.createElement("div");
o.id = idStr + "_Soup";
o.className = "frmStep";
o.innerHTML = template.replace(/xxxx/g, idStr);
document.body.append(o); // change this to append the item wherever it's supposed to go
}
createItem("JohnsMarket");
Any of that data seems like it could be stored in a hash keyed on the store name, including the chart itself; the rest is just string concatenation. But I agree, I'd try to move some of that onto the server side, even if it's just to retrieve the data used to create the charts.