Dynamic tabIndex attribute in JSX + React - javascript

How would I set the tabIndex attribute on a React component conditionally in the same way, say the disabled attribute is set?
I need to be able to set the value and/or remove the attribute all together.
First try was to make the entire attribute key and value a variable:
<div { tabIndex } ></div>
but the compiler complains.
Second thought was to:
const div;
if( condition ){
div = <div tabIndex="1"></div>
}else{
div = <div></div>
}
However, this is not desirable since my actual components have tons of attributes on them and I'd end up having large amounts of duplicate code.
My only other thought was to use a ref, then use jQuery to set the tabindex attributes, but I would rather not have to do it that way.
Any Ideas?

You can do it using the attribute spread operator:
let props = condition ? {tabIndex: 1} : {};
let div = <div {...props} />

I believe there is a simpler way (than Aaron's suggestion).
React removes an attribute from a JSX element if that attribute's value is null or undefined. I'd need this to be confirmed by someone who knows for sure.
Therefore you can use something like this:
let t1 = condition ? 1 : null;
let div = <div tabIndex={t1}>...</div>;
The tabIndex attribute will be removed if t1 is null.

For example, we have three attributes, tabIndex, class and id.
let tabIndex;
let id;
let className = "tab";
let props = {
tabIndex,
className,
id,
}
let div = <div {...props} />
undefined/null value props will not add in div, so the render result is
<div class="tab" />

Related

elements attributes return "undefined" for no reason

i have this piece of code:
function RemoveFromCart(id)
{
var items = document.getElementById("overview").children;
for(var i = 0; i < items.length;i++)
{
console.log(items[i]);
console.log(items[i].value);
}
}
the first log returns the actual element:
<div class="overview-item" value="0" data-total="5">1X item name - 5€<button onclick="RemoveFromCart(0)"></button></div>
but the second log returns
undefined
why is it doing this?
why isn't it returning the value of the elements "value" attribute?
and how do i go about fixing it?
<div> element nodes don't have a "value" property. That's only for <input> and other form controls. If you put a "value" attribute in the tag, you have to use .getAttribute() to fetch the value.
Depending on what you're trying to do, you can inspect the children elements and check the "nodeType" property so you know what/how to access stuff.
You are already using data-* attribute at data-total="5", as pointed out by #Pointy <div> elements do not have a .value property. You can substitute data-value="0" for value="0" and use HTMLElement.dataset to get or set the value.
console.log(items[i].dataset.value);

How to react to a specific style attribute change with mutation observers?

I've been experimenting with Mutation Observers, so far I can apply the relevant functions to react upon adding, removing elements and so on. Now I am wondering, is there a way to target a specific change within a specific style attribute? I know I can observe for attribute changes, but I just don't know how to observe for a specific attribute modification. For example, if the z-index value of #childDiv changes to 5678, modify the style of the parentDiv in order for it to be shown.
<div id="parentDiv" style="display:none;">
<div id="childDiv" style="z-index:1234;">
MyDiv
</div>
</div>
As per the documentation use attributeFilter array and list the HTML attributes, 'style' here:
var observer = new MutationObserver(styleChangedCallback);
observer.observe(document.getElementById('childDiv'), {
attributes: true,
attributeFilter: ['style'],
});
var oldIndex = document.getElementById('childDiv').style.zIndex;
function styleChangedCallback(mutations) {
var newIndex = mutations[0].target.style.zIndex;
if (newIndex !== oldIndex) {
console.log('new:', , 'old:', oldIndex);
}
}
Sorry for offtop.
Conception React is no mutations. If you need to listen some changes of some element (style for example). You can use componentDidUpdate and get element from #refs.parentDiv (set ref before this in render function <div id="parentDiv" ref="parentDiv" style="display:none;">) and after check style and set you z-Index value before new render.

When to access the attribute (vs the property)?

I gather from this post that almost always one wants to be accessing the DOM property, not the HTML attribute.
So what are the rare useful exceptions? In what situation is accessing the HTML attribute better than accessing the DOM property?
Sometimes the attribute doesn't map to changes in the property.
One example is the checked attribute/property of a checkbox.
DEMO: http://jsfiddle.net/mxzL2/
<input type="checkbox" checked="checked"> change me
document.getElementsByTagName('input')[0].onchange = function() {
alert('attribute: ' + this.getAttribute('checked') + '\n' +
'property: ' + this.checked);
};
...whereas an ID attribute/property will stay in sync:
DEMO: http://jsfiddle.net/mxzL2/1/
<input type="checkbox" checked="checked" id="the_checkbox"> change me
var i = 0;
document.getElementsByTagName('input')[0].onchange = function() {
this.id += ++i;
alert('attribute: ' + this.getAttribute('id') + '\n' +
'property: ' + this.id);
};
And custom properties generally don't map at all. In those cases, you'll need to get the attribute.
Perhaps a potentially more useful case would be a text input.
<input type="text" value="original">
...where the attribute doesn't change with changes from the DOM or the user.
As noted by #Matt McDonald, there are DOM properties that will give you the initial value that would reflect the original attribute value.
HTMLInputElement.defaultChecked
HTMLInputElement.defaultValue
A rare exception is the case of attributes of a <form> element that could clash with elements in the form. For example, consider the following HTML:
<form id="theForm" method="post" action="save.php">
<input name="action" value="edit">
</form>
The problem is that any input within a form creates a property corresponding to the input's name in the form element, overriding any existing value for that property. So in this case, the action property of the form element is a reference to the <input> element with name action. If that input did not exist, the action property would instead refer to the action attribute and contain the string "save.php". Therefore for properties of form elements corresponding to attributes, such as action and method, it's safest to use getAttribute().
var form = document.getElementById("theForm");
// Alerts HTMLInputElement in most browsers
alert( form.action );
// Alerts "save.php"
alert( form.getAttribute("action") );
// Alerts "post" because no input with name "method" exists
alert( form.method );
This is unfortunate; it would have been better if this mapping did not exist, since the elements property of the form already contains all the form elements keyed by name. I think we have Netscape to thank for this one.
Live demo: http://jsfiddle.net/z6r2x/
Other occasions to use attributes:
When accessing custom attributes, such as <div mymadeupattr="cheese"></div>
When serializing the DOM and you want values from the original HTML for input attributes such as value and checked.
I can only come up with 2 more situations where accessing/setting attribute would have benefits
over property.
Style attribute:
In a case where you are not allowed to use any framework, you can use style attribute to set multiple styles at once like so:
elem.setAttribute( "style", "width:100px;height:100px;" );
instead of doing this:
elem.style.width = "100px";
elem.style.height = "100px";
or this:
var styles = {width: "100px", height: "100px"}, style;
for( style in styles ) {
elem.style[style] = styles[style];
}
Be aware that setting style attribute overwrites the previous one. And its probably better to write
a multiple style setter function anyway.
Href attribute:
A href attribute will usually contain a value like "/products", however the property will contain the resolved url, as in:
"http://www.domain.com/products" instead of what you really want: "/products". So if you wanna do something dynamically with
links, then reading the href attribute instead of property is better because it has the value you intended it to be.
Update
I suddenly found 2 more uses and I am sure there are more like this.
If you want to see if an element has custom tab index set, the easy way is to see if the element has the attribute. Since the default
value for .tabIndex-property depends on element and cannot be easily used to see if the element has custom tabIndex.
Seeing if element has a custom .maxLength property. This cannot be seen from property either:
document.createElement("input").maxLength
//524288
It is impossible to tell if the value 524288 was there intentionally without dealing with the attribute.

getting the value of a div in jquery?

i wanted to get the value of a hidden div in jquery i.e.
<div id="text">hello i am the value, you want</div>
and i want insert this value into a another div in jquery i.e.
$('#bio').html($value);
EDIT:
i forgot to mention that it had to be the text within the block div sorry i.e. its parent
<div class="block" id="status_13">
<div id="text">.......</div>
</div>
i.e.
$('.block').click(function(){
$('#bio').html($('$text').html());
If your #text element contains HTML you might want to do:
$('#bio').html($('#text').html());
If you are only concerned with the literal text of #text then you can do:
$('#bio').text($('#text').text());
Of course, if you want to store the text in a variable first, you can do so:
var textValue = $('#text').text();
$('#bio').text(textValue);
In regard to your later edit:
$('.block').bind('click', function() {
var thisTextValue = $(this).children('.text').first().html();
$('#bio').html(thisTextValue);
});
Notice that I assumed the child div is marked with a class and not an id. Based on your description, it sounds like you have multiple "block" elements which each contain a "text" element. If that is the case, then $('#text') will always return the first "text" element in the document; IDs are unique in the document.
Don't use $ for variables (like $value), just value
var value = $('#text').html();
Did you try
$('#bio').html($('#text').html());
I think this would work
//get the value from hidden field and store it in the variable 'valueYouWant'
var valueYouWant = $("#text").html();
//set it in other field
$("#bio").html(valueYouWant);
edit:
More information can be found here

How to access HTML element without ID?

For instance in the snippet below - how do I access the h1 element knowing the ID of parent element (header-inner div)?
<div id='header-inner'>
<div class='titlewrapper'>
<h1 class='title'>
Some text I want to change
</h1>
</div>
</div>
Thanks!
function findFirstDescendant(parent, tagname)
{
parent = document.getElementById(parent);
var descendants = parent.getElementsByTagName(tagname);
if ( descendants.length )
return descendants[0];
return null;
}
var header = findFirstDescendant("header-inner", "h1");
Finds the element with the given ID, queries for descendants with a given tag name, returns the first one. You could also loop on descendants to filter by other criteria; if you start heading in that direction, i recommend you check out a pre-built library such as jQuery (will save you a good deal of time writing this stuff, it gets somewhat tricky).
If you were to use jQuery as mentioned by some posters, you can get access to the element very easily like so (though technically this would return a collection of matching elements if there were more than one H1 descendant):
var element = $('#header-inner h1');
Using a library like JQuery makes things like this trivial compared to the normal ways as mentioned in other posts. Then once you have a reference to it in a jQuery object, you have even more functions available to easily manipulate its content and appearance.
If you are sure that there is only one H1 element in your div:
var parent = document.getElementById('header-inner');
var element = parent.GetElementsByTagName('h1')[0];
Going through descendants,as Shog9 showed, is a good way too.
It's been a few years since this question was asked and answered. In modern DOM, you could use querySelector:
document.querySelector('#header-inner h1').textContent = 'Different text';
<div id='header-inner'>
<div class='titlewrapper'>
<h1 class='title'>
Some text I want to change
</h1>
</div>
</div>
The simplest way of doing it with your current markup is:
document.getElementById('header-inner').getElementsByTagName('h1')[0].innerHTML = 'new text';
This assumes your H1 tag is always the first one within the 'header-inner' element.
To get the children nodes, use obj.childNodes, that returns a collection object.
To get the first child, use list[0], that returns a node.
So the complete code should be:
var div = document.getElementById('header-inner');
var divTitleWrapper = div.childNodes[0];
var h1 = divTitleWrapper.childNodes[0];
If you want to iterate over all the children, comparing if they are of class “title”, you can iterate using a for loop and the className attribute.
The code should be:
var h1 = null;
var nodeList = divTitleWrapper.childNodes;
for (i =0;i < nodeList.length;i++){
var node = nodeList[i];
if(node.className == 'title' && node.tagName == 'H1'){
h1 = node;
}
}
Here I get the H1 elements value in a div where the H1 element which has CSS class="myheader":
var nodes = document.getElementById("mydiv")
.getElementsByTagName("H1");
for(i=0;i<nodes.length;i++)
{
if(nodes.item(i).getAttribute("class") == "myheader")
alert(nodes.item(i).innerHTML);
}
Here is the markup:
<div id="mydiv">
<h1 class="myheader">Hello</h1>
</div>
I would also recommend to use jQuery if you need a heavy parsing for your DOM.

Categories

Resources