Overwrite html div class element - javascript

I'm trying to add a duplicate element with a different class name as javascript won't add a duplicate object.
Expectations -
I added a button with an event listener on to grab the parent element html and change the class of it but it changes the class of old element as well.
Goal is to get a duplicated element in form if someone got multiple phone no. with button you should get an another input option
Here's my code for, doesn't work as i told
add_button.addEventListener('click', e=>{
const data = e.target.parentElement.parentElement
// Grabs the parent element on height 2
console.log(data) // Got the expected data
// ran_value = Math.floor((Math.random() * 100000) + 1); // Tried this function to generate a random value for class
var data_new = data // Created another instance of data
data_new.setAttribute('class', '1') //add class name
console.log(data_new) // changes the class name
// paramsDiv.appendChild(data)
});
Here's my result which I am getting
While in expected result, it should have changed the class name or added it in 2nd div only so duplicate div element can be appended into form paramsDiv.
Expected result is ->

Donot assign with var data_new = data instead clone the node with var data_new = data.cloneNode(true) Reference
Assigning the dom object to a new variable will not create a new independent copy. Instead both variables will point to same location.
If you want to insert the element as the first child, you can make use of Node.insertBefore()
Reference
Working Fiddle
const add_button = document.getElementById('add-button');
add_button.addEventListener('click', e => {
const data = e.target.parentElement.parentElement
// Grabs the parent element on height 2
console.log(data) // Got the expected data
// ran_value = Math.floor((Math.random() * 100000) + 1); // Tried this function to generate a random value for class
var data_new = data.cloneNode(true); // Created another clone instance of data
data_new.setAttribute('class', '1') //add class name
console.log(data_new) // changes the class name
// paramsDiv.appendChild(data)
});
<div>
Content
<button id="add-button">Add</button>
</div>

The reason it happens is because when you assign data to new_data, you are not creating a new object. You are simply telling new_data to point at data. For that reason, when you change new_data, data changes aswell. In order to create a completely new element, try this:
var data_new = data.cloneNode(true);

I don't know exactly your code but you could try to use nodeClone(), see the documentation: https://developer.mozilla.org/fr/docs/Web/API/Node/cloneNode
because the problem you have here is probably the "referencing".
Tell me how it goes.

Related

Adding a value to a dynamically created element and then having that value pass to another html page when that element is clicked

The elements are created in a for loop. I have tried storing each element ID in an array but it and using it but its always set to the last value the for loop ran through. Tried solving this problem with closures and still nothing works.
Heres a function I have after for loop, with i being passed in each time. moreinfolink is an empty array initialised outside the for loop. idarr is another array with different values in, which I want to reference using the moreinfolink array. Essentially when each element is clicked, the id it has based on its position in the moreinfolink should be used to then get its relevant position in the idarr, which are passed on to another page. And that pages content is genered using an API, for which we need the correct id (found in the idarr). Hope Im making sense.
function passthrough (a){
moreinfolink[a] = document.createElement("a");
moreinfolink[a].id = a;
newmoreinfo.appendChild(moreinfolink[a]); /* element I created elsewhere */
moreinfolink[a].innerHTML = "ID position in array is " + moreinfolink[a].id;
moreinfolink[a].href = "respage.html";
moreinfolink[a].onclick = moreinfo(idarr, moreinfolink[a].id); }
Both the overall array of returned ids (idarr) and each links relevant reference id (moreinfolink[a]) is passed into this function below upon the click event. Problem is that the last id is always passed through, so no matter which link you click it always passes through the last id the loop ended with instead of the one that should be assigned to that particular element.
function moreinfo (relarr, val) {
var carryover = [];
carryover.push(val);
window.name = carryover;
console.log("carryover is " + carryover)}
The function below is called when the other page is opened.
function generateapage () {console.log(window.name);}
You can add query stirng to href:
moreinfolink[a].href = `/respage&id=${moreinfolink[a].id}`;
Then you can read it when other pages load:
let id = new URLSearchParams(window.location.search).get('id')

Modifying an HTML Element through a JS Class

When defining a method on a user defined class that includes an HTML element JS throws a TypeError saying object.method is not a function.
My hunch is when only returning document.createElement the class inherits HTML object methods that prevent user defined methods from working? So my thought was to contain the HTML object as an element within an array, but still no dice.
class inputBox {
constructor(attributeList){
let element = document.createElement('input')
//just creating a unique ID here
attributeList.id = Math.random().toString(36).substr(2, 16);
for (let attr in attributeList){
this[attr] = attributeList[attr]
element.setAttribute(attr,this[attr])
}
return [element,attributeList]
};
updateValue(newValue) {
let element = document.querySelector(`#${this[1].id}`)
return element.value = newValue
};
}
this works fine
document.body.appendChild(inputBox1[0])
this not so much (note: there is no [0] since I'm querying the DOM)
inputBox1.updateValue("hello")
The idea is you could call something like the following with multiple parameters
var inputBox1 = new inputBox({type:'email', placeholder:'Your email'})
I think this is achievable with jquery, but was attempting a vanilla approach as learning exercise. Thx
Whenever you explicitly return an object from a constructor, the return value will be just that object, and not an instance of the class. When you do
return [element,attributeList]
what is returned is just a plain array, without anything connected to an inputBox, so proceeding to reference an inputBox class method on that array won't work.
Instead, put the element and attributeList onto the instance.
By putting the element onto the instance, you can also avoid creating a dynamic unique ID for each element (which is a code smell) - rather, just reference the this.element:
class inputBox {
constructor(attributeList){
this.element = document.createElement('input');
this.attributeList = attributeList;
for (const attr in attributeList){
this.element.setAttribute(attr,this.attributeList[attr]);
}
}
updateValue(newValue) {
this.element.value = newValue;
}
}
Still, unless there's going to be more code in the inputBox, there doesn't seem to be any use of the class here - after construction, its only exposed functionality is to set the value of the input, which could be done less obscurely by just using a reference to the input. Consider having a function that assigns the attributeList to the element's attributes, and then just using the plain element, eg:
const myInput = assignAttributes(attributeList);
// ...
myInput.value = 'newValue';

iterate inside a new JQuery object

I need to pass some html code as a parameter, however, before I pass it, I need to change some src attribute values.
I cannot use lastIndexOf or any of those to modify the html value since I don't know which value the src's will have.
What I'm trying to do then, is to create an object containing the html, and then alter that object only. I don't want to alter the actual webpage.
is this possible??
What I did first was this:
$('[myImages]').each(function() {
var urlImg = "../tmpFiles/fileName" + counter;
$(this).attr('src', urlImg);
counter++;
});
So finally, I had the desired code like this:
myformData = { theChartCode: $('#TheDivContainingTheHTML').html() }
However, this actually changes the image sources on the webpage, which I don't want to.
Then I thought I could create a JQuery object with the html so I could alter that object only like this:
var $jQueryObject = $($.parseHTML($('#TheDivContainingTheHTML').html()));
But now, I can't figure out how to iterate within that object in order to change the src attribute's values of the desired images.
Any help will be really appreciated ;)
There are several ways to do It. First would be creating a clone of target element and use the same on the Fly. You can do like below:
var Elem = $('#TheDivContainingTheHTML').clone();
now do whatever you want like iterate, alter,insert,remove.
var allImages =$(Elem).children("img");
Thanks Much!
Depending on when you want to change the object, solution will be different. Let's pretend you want to change it after you click another element in the page. Your code will look like that :
var clonedHTML;
$('#clickable-element').click(function() {
var $originalHTML = $(this).find('.html-block');
var $cloneHTML = $originalHTML.clone();
$cloneHTML.find('.my-image').attr('src', 'newSrcValue');
clonedHTML = $cloneHTML.clone();
return false; //Prevents click to be propagated
});
//Now you can use `clonedHTML`
The key point here is the clone method : http://api.jquery.com/clone/.
You can clone the elements:
var outerHTML = $collection.clone().attr('src', function(index) {
return "../tmpFiles/fileName" + index;
}).wrapAll('<div/>').parent().html();
You can also use the map method:
var arr = $collection.map(function(i) {
return $(this).clone().attr('src', '...').prop('outerHTML');
}).get();

Naming of input elements in a dynamically created form

I am very new to Javascript, so sorry if I don't use the correct terminology.
I have a form that can dynamically grow. In other words I have buttons that will add labels and input fields to whenever the user clicks it.
At the end of the form, I'd like to have some "done" button that runs another JavaScript function.
However I notice that all of the input fields have the same id (since the function makes the id the same each time).
What is the correct way to access these variables???
Below is the function to dynamically create the fields.
I havent written the function to use the form yet.
function buildDefaultFields(){
// Define container
var chargeItem_container = document.getElementById("chargeItem_container");
// INPUT Start Date
chargeItem_container.appendChild(document.createTextNode('Start Date: '));
var startDate = document.createElement("input");
startDate.type = 'date';
startDate.name = 'startDate';
startDate.id = 'startDate';
chargeItem_container.appendChild(startDate);
chargeItem_container.appendChild(document.createElement("br"));
}
Don't use an id if its not going to uniquely identify a single element, instead use a class
startDate.className = 'startDate';
then use getElementsByClassName to retrieve them
var elements = document.getElementsByClassName ('startDate');// then loop through the elements
You should dynamically add the elements such that each element gets a new id. You could use a simple counter to append to your id names.
For example, if you keep a global var count = 0, then your first id could be 'startDate-' + count which will be startDate-0, then perform an increment on count, so that the next time you add an element, it will get the id 'startDate-' + count = startDate-1.
Hope that helps.

JSON how find another value at the same index from a value in Javascript Object

A simple question I'm sure, but I can't figure it out.
I have some JSON returned from the server
while ($Row = mysql_fetch_array($params))
{
$jsondata[]= array('adc'=>$Row["adc"],
'adSNU'=>$Row["adSNU"],
'adname'=>$Row["adname"],
'adcl'=>$Row["adcl"],
'adt'=>$Row["adt"]);
};
echo json_encode(array("Ships" => $jsondata));
...which I use on the client side in an ajax call. It should be noted that the JSON is parsed into a globally declared object so to be available later, and that I've assumed that you know that I formated the ajax call properly...
if (ajaxRequest.readyState==4 && ajaxRequest.status==200 || ajaxRequest.status==0)
{
WShipsObject = JSON.parse(ajaxRequest.responseText);
var eeWShips = document.getElementById("eeWShipsContainer");
for (i=0;i<WShipsObject.Ships.length;i++)
{
newElement = WShipsObject.Ships;
newWShip = document.createElement("div");
newWShip.id = newElement[i].adSNU;
newWShip.class = newElement[i].adc;
eeWShips.appendChild(newWShip);
} // end for
}// If
You can see for example here that I've created HTML DIV elements inside a parent div with each new div having an id and a class. You will note also that I haven't used all the data returned in the object...
I use JQuery to handle the click on the object, and here is my problem, what I want to use is the id from the element to return another value, say for example adt value from the JSON at the same index. The trouble is that at the click event I no longer know the index because it is way after the element was created. ie I'm no longer in the forloop.
So how do I do this?
Here's what I tried, but I think I'm up the wrong tree... the .inArray() returns minus 1 in both test cases. Remember the object is globally available...
$(".wShip").click(function(){
var test1 = $.inArray(this.id, newElement.test);
var test2 = $.inArray(this.id, WShipsObject);
//alert(test1+"\n"+test2+"\n"+this.id);
});
For one you can simply use the ID attribute of the DIV to store a unique string, in your case it could be the index.
We do similar things in Google Closure / Javascript and if you wire up the event in the loop that you are creating the DIV in you can pass in a reference to the "current" object.
The later is the better / cleaner solution.
$(".wShip").click(function(){
var id = $(this).id;
var result;
WShipsObject.Ships.each(function(data) {
if(data.adSNU == id) {
result = data;
}
});
console.log(result);
}
I could not find a way of finding the index as asked, but I created a variation on the answer by Devraj.
In the solution I created a custom attribute called key into which I stored the index.
newWShip.key = i;
Later when I need the index back again I can use this.key inside the JQuery .click()method:
var key = this.key;
var adt = WShipsObject.Ships[key].adt;
You could argue that in fact I could store all the data into custom attributes, but I would argue that that would be unnecessary duplication of memory.

Categories

Resources