Replicate HTML source of a DOM element in current state - javascript

On my page there are a few <select> html elements, each of them with multiple <option> values. I would like the same <select> elements to be used in a MapBox description toolkit, which expects me to pass a HTML source into its setHTML method.
The simple way I do it now is:
var tableOption = document.getElementById(selectId);
var html = tableOption.innerHTML;
return "<select>" + html + "</select>";
This works, however it has a drawback of passing the original html source, therefore it does not reflect which option is selected right now. I know I can get currently selected option with value or selectedIndex, and it should be possible to parse the HTML I have obtained and remove and add selected property to a corresponding node in JS, however this seems a bit complicated.
Is there some easier way how to get a HTML source which could be used to construct a copy of a select element with the exact selection state it has now?
I would prefer a solution without jQuery if possible.

You could just wrap your select in another element. Then you'd be able to select it by id, get the parent node, then the parent node's innerHTML. If you want to show which option is currently selected, you can place the selected attribute on it.
document.getElementById('selectId').addEventListener('change', function() {
var opts = this.getElementsByTagName('option');
for (var i = 0; i < opts.length; i++)
opts[i].removeAttribute('selected');
this.querySelector('option:checked').setAttribute('selected', 'selected');
console.log(this.parentNode.innerHTML);
});
<div class="select-wrapper">
<select id="selectId">
<option>Yes</option>
<option>No</option>
</select>
</div>

Just clone the element and then set the selectedIndex - things like event handlers probably wouldn't be copied though
I realize you asked for a simpler solution but I can't think of one much simpler considering it's only 4 lines
Fiddle https://jsfiddle.net/s8mb0mxp/2/
HTML
<select id="original">
<option>1</option>
<option>2</option>
<option>3</option>
</select>
<button>
Clone
</button>
<div id="target">
</div>
JS
$('button').on('click', function(){
var $original = $('#original');
var el = $original.clone(); // Clone the object
$('#target').append(el) // Attach the new object to an element
el.find('option')[$original[0].selectedIndex].setAttribute('selected', 'selected')
console.log(el[0].outerHTML)
});

Related

Get an array of DOM-Elements in vue js

I am trying to get an array of DOM-Elements in Vue.js. If I had the following HTML structure:
<select onchange="toggleDisability(this);" class="mySelect" id="mySelect1">
</select>
<select onchange="toggleDisability(this);" class="mySelect" id="mySelect2">
</select>
I could get all elements with the mySelect class with normal JS like:
var arraySelects = document.getElementsByClassName('mySelect');
Now I am trying to get the same thing with Vue $refs, but I am always getting the last element. it looks like:
<select id="selection-x" ref="Axis" #change="log($event)"></select>
<select id="selection-y" ref="Axis" #change="log($event)"></select>
and
log(selectElement){
var arraySelects = this.$refs['Axis'];
}
Of course there are also options ,so that #change event gets emitted, but it doesn't do what I want it to. I want to get an array of the elements with the same ref just like it works in the example above for normal JS, where you are getting an array of select elements whose class attribute equals to mySelect.
P.S. I know ref should be unique, but how could it be then used for this particular usecase?
No. It is not possible with ref and $refs. If you wish to do DOM manipulation then, use vue-directive or directly access DOM from the root element of the component like:
Vue.extend({
mounted() {
// Do what you want with your children.
const children = this.$el.querySelectorAll('.mySelect');
}
})
For me the best way to do this was to set a ref on the parent element (thanks joaner in original comment), but then I also needed to run my code in the "updated" hook so my data was loaded before trying to access the dom (I also have a v-if on the same element I want to reference children):
template:
<ul v-if="dataLoaded" ref="eventlist">
<li class="eventItem"></li>
<li class="eventItem"></li>
<li class="eventItem"></li>
</ul>
javascript:
updated() {
let eventItems = this.$refs.eventlist.children
console.log(eventItems)
}

select an element based off a select value

I am trying to take the value of a select element and match it to a dataset of another element to affect a transition on that element.
So I have two tags with data in them:
<select data-name="name goes here" updateElement()></select>
<select value="what ever option is picked" applyTransition()></select>
When ever you change the option of data-name it will update a variable that holds the element I am trying to apply the transition affect on.
The goal is when you change the select with the data-name it updates and element the other select applies a transition too.
I haven't shared any of the actual code because it is a lot and would like to just share what is needed.
Okay so I figured this out after banging my head against the console.
const yourElements = document.querySelectorAll(".your-class-name");
let selectedElement;
So if your elements have a data-property set you can "pluck" that one out.
for(let i = 0; i < yourElements.length; i++){
if(select.value === your-class-name[i].dataset.property){
selectedElement = document.querySelector(`[data-property=
${locationHands[i].dataset.property}]`);}
Then you should be able to see selectedElement as the element you want.
You can then use that variable where ever.
If you know of a better or more efficient way to achieve this, please let me know.

Appending a dynamic div in another previously dynamically created div

I'm attempting to add a div within another div, both of which are dynamically created. I'm honestly unsure why it's not adding it in within the newDiv
(function ($){
$.fn.dropdown = function(){
return this.each(function(){
//Gather information
var id = $(this).attr("id");
//Get the original selection and keep it as a reference
var original = $(this);
//Create a new div with a predefined class and taking the ID from the original HTML.
var newDiv = $("<div id='"+id+"' class='dropDownJs' />");
//Remove the id from the original HTML
original.removeAttr("id");
//Encapsulate the original dropdown with a new parent div
original.wrap(newDiv);
//Create children divs within the parent div for each option within the selection HTML.
original.children().each(function(){
//Grab crucial values from the original.
//The value of the option
var val = $(this).val();
//The text from the option (label)
var text = $(this).text();
//Child divs to create
var child = $("<div class='dropDownJsChild'></div>");
newDiv.append(child);
});
});
}
}(jQuery))
For all intensive purposes, this jQuery is manipulating this HTML snippet
<select id="test" class="dropdown">
<option value="something1">Something 1</option>
<option value="something2">Something 2</option>
<option value="something3">Something 3</option>
</select>
To clarify further:
<script>
$(document).ready(function(){
$(".dropdown").dropdown();
});
</script>
Unfortunately, the newDiv.add(child) isn't working, and I've also tried doing newDiv.append(child) which has also failed.
Edit: As it turns out, the OP is trying to create invalid HTML structures, wrapping option tags inside div tags or whatever, so lets close this
Dont create a div with the same id as an existing one and wrap them like here: original.wrap(newDiv); remove the id before this
Secondly, youre using the add function which is not what you are looking for, rather use append:
newDiv.append(child);
the add function extends the jquery object newDiv by the child. append moves elements into others within the DOM.
You need to use after method of original element:
var child = $("<div class='dropDownJsChild' />");
original.after(child);
And the reason why you can't use newDiv to append new elements is obvious from documentation for wrap:
A copy of this structure will be wrapped around each of the elements in the set of matched elements.
So wrapping element is not original element anymore, it's a copy of it and does not represend the original node.

Exclude Element from .html()

I have to remove a specific element (button with #add_phone) from .html() of jquery.
So here's the thing. At first there are field(phone number) + select(phone type) + button(#add_phone), and all three are enclosed in div as a container. And when I click the button, it will recreate that through .html().
The JS is as follows:
$('#add_phone').click(function() {
$('div.multiple_number:last').after('<div id="phone_div_id' + phone_div_id + '" class="multiple_number">'+ $('div.multiple_number').html() +'</div>');
...
//append a remove [-] button, etc...
});
and here's the html:
<div class="multiple_number" id="phone_div_id0">
<label>Phone Number(s):</label>
<input name="phone" id="phone[]" placeholder="Phone Number"/>
<select name="phone_type[]" id="phone_type">
<option value="1">Mobile</option>
<option value="2">Home</option>
<option Value="3">Office</option>
<option Value="3">Fax</option>
</select>
<input type="button" name="add_phone" class="add_phone_class" id="add_phone" value="ADD MORE" />
</div>
So in effect, I am creating multiple phone numbers for a form. But, here's the problem. Inside is an input type="button" (#add_phone button). And I would want to exclude it from .html().
I have tried:
$('div.multiple_number:not(#add_phone)').html()
$('div.multiple_number:not(input#add_phone)').html()
$('div.multiple_number:not(#add_phone)').not(#add_phone).html()
$('div.multiple_number:not(#add_phone)').not(input#add_phone).html()
And the class name counterpart instead of using id name. I wouldn't also want to place the #add_phone button outside the div, for aesthetics reason.
I'm a little bit unclear about what you're looking for, but I assume that when the #add_phone button is clicked, you want the form to be duplicated and added below it with the exception of the #add_phone button itself.
Working off that assumption, the following should work
$('#add_phone').click(function() {
var numberForms = $('div.multiple_number');
var newNumberForm = numberForms.eq(0).clone(true);
newNumberForm.find('#add_phone').remove();
newNumberForm.attr('id', 'phone_div_id' + numberForms.length);
numberForms.last().after(newNumberForm);
});
Here's a live jsfiddle demo to show it working.
Your initial attempts didn't work for a few reasons. The main one being that :not() selector and .not() methods only operate on the element being selected. It doesn't filter based on child elements. Those methods would only work if the element you were selecting <div class="multiple_number" /> also had the ID add_phone.
Also, it is not recommended to use .html() as a way of cloning methods. Using string manipulation as an alternative to direct DOM manipulation can cause problems later on. Using .html() will force you to have to re-bind event handlers to the newly created DOM elements. The strategy I've provided above should be more future-proof, since it will also clone event handlers for any elements being copied. There are also cases where certain browsers will not replicate the original elements exactly when calling .html(), which is another reason to avoid it unless you have a specific reason for serializing your DOM elements as a string.
Try this instead :
var innerHTML = $("div.multiple_number").html()
.replace($("div.multiple_number input#add_phone").html(), "");
Good Luck

Obtain a HTML elements hidden value

I have a HTML element like so:
<select>
<option id="a" hidden"1">Abcdefgh</option
</select>
And, using javascript, I want to retreive the hidden value from the option element.
How do I do this?
var hiddenVal = document.getElementById( "a" ).hidden; // this doesnt work
Not all attributes map directly to properties. You should be able to use the native .getAttribute() to get the value of custom attributes.
var hiddenVal = document.getElementById( "a" ).getAttribute('hidden');
<select>
<option id="a" hidden="1">Abcdefgh</option>
</select>
Well first off your mark up on your HTMl is all off. You are missing an end tag on the element and you would need to put hidden="1" with the equals and quotes. But is hidden even a valid attribute for an option element?? I dont think it is.

Categories