<ul>
{
this.state.pics ? this.state.pics.map((pic, index) => {
return (
<li key={index}>
<img src={pic.url} height="200" alt="Image preview..." />
<select data-id={index} onChange={this.setValue}>
<option value="1" >Monday</option>
<option value="2">Tuesday</option>
<option value="3">Wednesday</option>
<option value="4">Thursday</option>
<option value="4">Friday</option>
<option value="4">Saturday</option>
<option value="4">Sunday</option>
</select>
</li>
)
}) : ""
}
</ul>
On every change, I would like to get the value of data-id attribute which is nothing but value of index . or is there a way to directly access the value of key attribute of li . I am using react . Also is it a good practice in react to directly access the dom by query selector
const setValue = (e) => {
console.log(e.target.getAttribute('data-id'))
}
The onChange callback gets the normal javascript event object which can be used to access the attribute you want.
Apart from pure JS based solutions of accessing the DOM via event APIs (in your case), you can also use the Refs feature of React
But as the docs themselves say
Avoid using refs for anything that can be done declaratively.
In your case, accessing the select element's custom attributes are pretty straightforward
Create a ref to the element you wish to access the DOM
Assign it to a variable which is accessible in your event callback
Access the variable ,which has the DOM reference in your function.
<select
ref={select => (this.selectElement = select)}
data-id={1}
onChange={this.setValue}>
A sample can be found here in the CodeSandox link
And to answer your other question "Also is it a good practice in react to directly access the dom by query selector" - I'd say use that as a last resort , most of the problems can be solved by moving around props and states in component heirarchy.
Recommended reading
Lifting State Up
Thinking in React
You could try something like this $(this).parent().attr('data-id');
Related
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)
}
I got 1 select attribute
I got something to trigger for the select
first:
<select id="select-room" data-room="inhouse"></select>
second:
<select id="select-room" data-room="ar_account"></select>
I have already done this the thing is when I make a function for this thing it wont work like:
$('#select-room').on('change','[data-room="inhouse"]', this.Change1);
$('#select-room').on('change','[data-room="ar_account"]', this.Change2);
the thing is these 2 functions wont work
There should not be same id in one DOM. Because when you do so, the DOM will search for the id (here "select-room") from the top and it will consider the first one comes across.
So this is a bad idea to use the same id multiple times. Use class instead.
<select class="select-room" data-room="inhouse"></select>
<select class="select-room" data-room="ar_account"></select>
$('.select-room[data-room="inhouse"]').on('change', this.Change1);
$('.select-room[data-room="ar_account"]').on('change', this.Change2);
Firstly, you should not use same id for multiple elements, selector will only target first matched element, I have changed it to class in the code. If the issue is that data-room is changing for element, you can use event delegation here and attach event to document instead or to some parent element, like this:
<select class="select-room" data-room="inhouse"></select>
<select class="select-room" data-room="ar_account"></select>
$(document).on('change', '.select-room[data-room="inhouse"]', this.Change1);
$(document).on('change', '.select-room[data-room="ar_account"]', this.Change2);
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)
});
Is it possible to use jquery to get an html5 data attribute from a select option?
<select id="change-image">
<option value="cool" data-image="myimage.jpg">Cool</option>
</select>
$("#pet-tag-id").change(function() {
var src = $("#change-image").data("image");
$("#image-preview").attr("src", src);
});
<img id="image-preview">
Yes.
You even did it in the correct manner. jQuery will pull HTML5 data attributes into its internal expando data object for elements. So you can access them just by name.
The only thing that is incorrect is, that you don't call .data() on the correct element. You're calling it on the <select>, but you need to grab the selected option element. Like
var src = $("#change-image option:selected").data("image");
$("#change-image").change(function() {
var data_image = $(this).children('option:selected').attr('data-image');
});
I want to be able to choose the Battery 9 inside the dropdownlist.
I want the image of Battery 9 to show in the img tag.
Am I doing something wrong?
HEAD
function checkBatteryLife(){
if(document.getElementById('batterylifes').value == 'batterylife9'){
document.getElementsByTagName('batteryID').src = 'battery9.png';
}
BODY
<img alt="" src="" name="batteryID" onclick="checkBatteryLife()">
</br>
<select id="batterylifes" onchange="checkBatteryLife()">
<option name="batteryIMG" value="batterylife9">Battery 9</option>
</select>
The getElementsByTagName method will return a collection of tags by name, such as IMG or SELECT. Passing in the name attribute of a tag will not yield any results.
You should probably use getElementById and pass in the id of the element:
function checkBatteryLife() {
if(document.getElementById('batterylifes').value == 'batterylife9')
{
document.getElementsById('batteryID').src = 'battery9.png';
}
}
..
<img alt="" src="" id="batteryID" onclick="checkBatteryLife()" />
<br />
<select id="batterylifes" onchange="checkBatteryLife()">
<option name="batteryIMG" value="batterylife9">Battery 9</option>
</select>
You can also use getElementsByName which will return a collection of DOM elements with the specified name property, and then iterate through it to find the correct one.
You need .getElementsByName() function instead of .getElementByTagName():
document.getElementsByName('batteryID')[0].src = 'battery9.png';
As .getElementsByName() function returns list,and not a single element, for accessing list's element you need to use [] square brackets.Specifically you need first matched element with name="batteryID", that's why you should use[0].
Firstly, it is not cross-browser compatible to get the value of the selected option by simply reading the value of the select. Instead, first detect the selected option then read ITS value.
var sel = document.getElementById('batterylifes');
if (sel.options[sel.options.selectedIndex].value == 'batterylife9') {
//your code here...
}
Secondly, as many have pointed out, you are mistakenly using getElementsByTagName to reference a single element by its name. You need getElementsByName(), though this is not cross-browser compatible either. Other options:
use jQuery or some other library
if you don't care about old browsers, use the new document.querySelector() method to select the element via CSS syntax
give the image an ID and use getElementById()