Issue while accessing element by dojo.byId dojo 1.8 - javascript

I am trying to access a div element text by using dojo.byId but it is returning the value which is set at first time the value is selected.It is somehow binding the value initially selected to the id of div and hence returning the same value even after I change the value to some other value.
var startDateLabel = dojo.byId("startDateLabel");
<label class="secondaryColor bold75Font floatRight" id="startDateLabel">${startDate} </label>
I tried to use registry.ById but since it is in a widget that is created more than once , it gives "id already registered error".For removing that , I also used destroyRecursive method but that also doesn't work.
Earlier, I used the id of container in which the widget is loaded and traversed to the children hierarchy to get the label value and it worked fine. but the child traversal code made it a bit messy.Something like
var startDateCont = registry.byId("startDateContainer");
var startDateLabel = startDateCont.domNode.children[1].children[1].children[1].innerHTML;
Is there any other way in dojo to achive this????

If you're using this inside a widget you should not even use IDs (or at least use generated IDs). The best way to get a reference to a DOM node while using a widget is by using attach points. An example, consider the following HTML:
<label class="secondaryColor bold75Font floatRight" data-dojo-attach-point="startDateLabel">${startDate} </label>
As you can see I introduced an attribtue called data-dojo-attach-point which allows me to give a name to the label (similar to an ID).
Then inside the widget you can now easily get a reference to that DOM node by using:
this.startDateLabel;
Just some extra information, you can also define events in a similar way by using data-dojo-attach-event. Make sure to read this part of the Writing your own widget article.

Related

Setting input value with JQuery doesn't always work

These questions are from looking at the single page app sample located here. Can anyone explain why attempts to set the value of an input control with JQuery does/does not work with the following conditions? I will include the HTML that is constant and then present a series of Javascript lines that I can't explain the behavior. First the HTML.
<form>
<div class="container-fluid">
<div class="data-container">
<div class="form-group">
<div class="row">
<div class="col">
<label>Region</label>
<input type="text" class="form-control request-region" id="regionfield" value="test" />
</div>
</div>
</div>
</div>
</div>
</form>
If I run this code it works as expected and the input box has a value of 99. Note that I'm setting the value in two different places because of the issue I found in the next sample.
$("#regionfield").val(44);
var $entry = $("div").find(".data-container");
$entry.find("#regionfield").val(99);
But if I remove that first line of code and just run this below the value of the input is "test". Why does setting the value fail now when it worked in the first instance?
var $entry = $("div").find(".data-container");
$entry.find("#regionfield").val(99);
Now if I save the HTML from the first code into a string, empty the control, then load it back, why does this code not result in the updated value of 99 but instead has the original value of "test"?
$("#regionfield").val(44);
var $entry = $("div").find(".data-container");
$entry.find("#regionfield").val(99);
var output = '';
output += $entry.html();
$entry.empty();
$entry.html(output);
Update I just noticed that I get different results when testing with Bootply vs Codeply. With Bootply the result for code sample #1 is 99 but on Codeply the result is "test". This makes me suspect the behavior is related to Bootstrap.
Simple Explanation:
The value attribute and the value property are not the same and are not connected outside of the initial load.
The value attribute is stored in the markup. This is what is initially rendered by the Browser. Unlike other properties, any subsequent changes to value through JavaScript are stored within the DOM itself.
The attribute/your markup is not updated when the value on the element is changed during the course of your application.
This means that because you're grabbing the markup as your test, you'll never see the value attribute change, but if you were to look at the actual DOM node you would see the current and correct value underneath the value property.
Longer Explanation:
Attributes in the Specification are called IDL 's and can be either reflective or non-reflective.
For more information see the HTML Standard here
A DOM Node's property and its HTML attribute are interchangeable from the point of rendering if the node is not altered - but also if specific attributes are changed.
Altering id and class in any way, whether directly on the DOM Node or within the Attribute object using the element.setAttribute method, will result in both values being changed.
id and class are reflective IDL attributes because they, in effect, watch their content attributes for changes and vice versa.
Alternatively checked and value IDL attributes are not reflective. When the value or checked properties are altered on either the DOM Node or the Attribute Object, it does not alter the corresponding attributes of the other.
Outside of those properties( there are more than id and class - though there's no real list of reflective vs not reflective - I would presume it's any property related to the identity of the Node in the DOM that would cause a re-render ) the content attributes and DOM Node properties are not bound together.
This makes using getAttribute and setAttribute useless if the intent is to update or get current data, because the current data is only found within the DOM Node properties.
Likewise, if you are trying to gauge whether a change in the value property has occurred by looking at the markup you will only see the original value.

jQuery caches elements selected?

So I'm using this code to:
$('.something').on('click', function () {
console.log($(this).data('id'));
}
And for some reason, if I modify the data-id using the inspector, jQuery still sees the id that was there in the beginning. However, I tried the same thing using JS and it does see the changes. This makes me wondering if jQuery caches in some way the elements selected and uses them instead of the actual DOM.
Can someone please explain what happens and how jQuery does the event binding in the background?
Later edit: I want to specify that I'm talking about the "data-" attribute that I put in the HTML, not about the '.data()' provided by jQuery. Not sure if it's the same thing.
jQuery caches elements selected?
No. But the data managed by data is stored in an object cache maintained by jQuery, keyed by a unique identifier jQuery adds to the element (so it can look up the data). data is only initialized from data-* attributes, it is not an accessor for them. It's both more and less than that.
If you're interested, you can see that as an "expando" property on the element instance, it'll start with "jquery" and have a long number attached to it (currently; it's undocumented — for good reason — so this may change):
var foo = $("#foo");
console.log(foo.data("info")); // hi there
console.log("Expando name: " + Object.getOwnPropertyNames(foo[0]).find(name => name.startsWith("jQuery")));
<div id="foo" data-info="hi there"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

Backbone Marionette Target Element in el with jQuery

I'm working on creating a basic question app to better understand backbone marionette. I'm my free-text questions right now use the same "#question-number-range id for setting the range of numbers users can enter when taking a survey. Then I split up the range and assign the min/max values accordingly.
This works great for the first free-text question view. But when I try to do the same thing on a second it ends up getting set to the first's min/max values because they have the same id.
What I'm wondering - is there a way I can do something like $(#el < '#question-number-range') to target just the input within the current view's el, rather than any input that has that id?
Or am I completely going about this wrong and need to maybe dynamically create the ids?
An id attribute is:
A unique identifier for the element.
There must not be multiple elements in a document that have the same id value.
so if you have duplicate ids then you don't really have (valid) HTML and all sorts of strange things can happen.
A better approach is to use a class to identify elements of interest. Then you could use #$('.whatever-the-class-is') to find the element within your view's el:
$ (jQuery) view.$(selector)
If jQuery is included on the page, each view has a $ function that runs queries scoped within the view's element. If you use this scoped jQuery function, you don't have to use model ids as part of your query to pull out specific elements in a list, and can rely much more on HTML class attributes. It's equivalent to running: view.$el.find(selector)
so #$(x) is the same as #el.find(x) and will limit your search to the view.

Where does jquery put .val() on a DIV?

jQuery (all versions tested up through 2.1.0) allows me to call .val("some value") on a DIV object to set a value on the DIV. It is not displayed and doesn't show up as an HTML5 data property in Chrome Developer Tools. And yet I can fetch the result later with a call to .val().
For example (from http://jsfiddle.net/X2nr6/ ):
HTML:
<div id="mydiv" style="display: none;">Some text</div>
<div id="debug"></div>
Javascript:
$('#mydiv').val('A value attached .');
$('#debug').text( $('#mydiv').val() );
Displayed result:
A value attached.
Where is the value stored? Not knowing where it is stored makes me worry that I am relying on a hack.
jQuery is just assigning to a value property on the div object (the HTMLDivElement instance for that div), even though it doesn't normally have one. Creating new properties on elements is allowed in every browser I've ever seen, so it works. I wouldn't use val with divs on a regular basis, though.
Here's a non-jQuery example:
var div = document.createElement('div');
console.log('value' in div); // false, divs don't normally have a value property
div.value = 42;
console.log('value' in div); // true, we've created a property on the element
console.log(div.value); // 42
Or the same sort of thing using jQuery:
var $div = $("<div>");
display(typeof $div.prop('value'));
$div.val(42);
display(typeof $div.prop('value'));
display($div.prop('value'));
This business of creating new, custom, non-standard properties on elements is called creating "expando" properties. They can be very handy. (jQuery uses them internally, for instance, to manage the data cache and a few other things — if you look closely at a DOM element you've set data on using data, you'll see a property with a name like jQuery1110028597884019836783; that's the key jQuery uses to find the element's data in jQuery's internal data cache. jQuery doesn't store the data in an expando on the element, because of IE garbage collection issues; it stores the key there, and the data in a JavaScript object.)
It stores it on a value property on the DOM object. You can see if by running your code and then inspecting the element in a DOM inspector. In Chrome, the value property will be listed under div#mydiv in the properties tab.
HTMLDivElement objects don't officially support such a property, so you are relying on a hack.
Use data() to store arbitrary data on an element.
$('#mydiv').data("myCustomValue", 'A value attached .');
Although the above answers are accurate, I'd like to complete something out.
jQuery is designed around the concept of wrapping all HTML elements in the jQuery object. That jQuery object happens to be an array that can hold more than one element.
jQuery also goes out of its way to hide this fact from you so that the average jQuery developer never has to worry about exactly what he has -- simply call the right method and the magic happens.
(You see this if you do a $(".someClassYouHaveLotsOf").hide() or $(".someClassYouHaveNoneOf").hide()`.)
jQuery's val() method is just a wrapper for accessing an HTML input element's value property. Since jQuery doesn't throw errors unless there is really no way what-so-ever, it silently helps you by accessing the value property on whatever HTML element it happens to have. div span or whatever.
In most browsers, this works -- mostly enough.
If you are really interested in setting values on HTML elements for use later, the data() method is far better suited. Straight HTML would use <element>.setAttribute("data-key", "value");
And that is about the only time you'll see me using the HTML attributes over properties, BTW.

Problem with using dojoAttachpoint while adding /removing style

I have a div as show below:
<div id="xyz" dojoAttachPoint="xyz" style="display: none;"> </div>
Now I want to show/ hide it. If I do it using dojo.byID it works. But if I do it using dojoAttachppoint it does not work properly. I don't get any errors but changes don't take place.
dojo.byId("xyz").style.display="none";
dojo.byId("xyz").style.display="";
this.xyz.style.display ="none";
this.xyz.style.display ="";
What can be the problem?
Are you using the above in a template within a class declared using dojo.declare with base class dijit._Templated?
Your understanding of attach points is flaky. When dijit._Templated parses the tenmplate, and when it sees a "dojoAttachPoint" attribute, it will create a property in the dijit object with the attach point's name. Therefore, "xyz" is a property in the dijit class object. The name is taken from the attribute called "dojoAttachPoint" when the template is being read. The dojoAttachPoint attribute is no longer used afterwards.
If "this" points to the dijit class you created, this.xyz will point to the DOM element (i.e. the div), never a widget. Therefore it does not have a "domNode" property. Trace the source code in dijit/_Templated.js line#191 to confirm.
Therefore, you need to do some console.log calls to confirm that this.xyz is returning the correct div. If it does, then you can try dojo.style(this.xyz, "display", "none") to see if you can hide it etc.
As to why this.xyz.style.display = "none" won't work, it may be a browser-specific thing, as it should do the same thing as dojo.style. You'll need to dig deeper to find out.

Categories