Ext.DomHelper.useDom set to true isn't working - javascript

I'm using ExtJs 3.4 and have the following code to create a hidden field:
box.hidden = this.el.insertSibling({
tag: 'input',
type: 'hidden',
value: itemVal,
name: (this.hiddenName || this.name)
}, 'before');
However, when itemVal is a json-string (or a string with quotation characters) it creates an element that looks like:
<input type="hidden" value="[" 635f7ede-7add-415f-8461-548d17027cac.group","bbe2x:101"]"="" name="selector_account_ef8e33ca71e749dca21997f51b404e23" id="ext-gen1766">
The problem is that it cocatenates the html for performance. So I want to, in this case, create the element by setting Ext.DomHelper.useDom to true. Should be an easy fix, right? But the inner code that checks the useDom variable checks against the private object that is passed to Ext.apply function instead of using Ext.DomHelper.useDom. So it doesn't matter if i set Ext.DomHelper.useDom to true inside the function that checks it, it is never true. Se the ExtJs code here:
http://docs.sencha.com/ext-js/3-4/source/DomHelper-more.html
// private
function doInsert(el, o, returnElement, pos, sibling, append){
el = Ext.getDom(el);
var newNode;
if (pub.useDom) {
...
} else {
...
}
return returnElement ? Ext.get(newNode, true) : newNode;
}
I found an old bug report for this that was closed, (http://www.sencha.com/forum/showthread.php?76966-CLOSED-3.0.0-DomHelper-s-useDom-bug) but I don't understand why and HOW I can set useDom to true.
Of course it's simple to fix it by replacing " to " but I want to understand it.

Related

Binding with regex does not trigger on model update

I have a sap.m.Input with a regex binding. When my input is "A", "B" or "C" my text is black, otherwise it becomes red through CSS.
oComponent.attachValidationError(function(oEvent) {
oEvent.getParameter("element").addStyleClass("become-red");
});
oComponent.attachValidationSuccess(function(oEvent) {
oEvent.getParameter("element").removeStyleClass("become-red");
});
var oInput = new sap.m.Input( {
value: {
path: "Qux>/foo/0/bar/0/baz",
type: new sap.ui.model.type.String(null, {
search: new RegExp("^[ABC]$")
})
}
});
When the value is "A" and I change it to "B", this works properly.
Then, if I do
oModelQux.setProperty("/foo/0/bar", [{
"baz" : "A"}]);
This works properly, the value becomes "A" again. My problem is that when I change the value of the input to a value which is not alllowed (e.g. "D"), and then I try my code
oModelQux.setProperty("/foo/0/bar", [{
"baz" : "A"}]);
nothing happens. The input does automatically update to "A", it just leaves the string "D" in red.
The binding should avoid that wrong values are stored in the model. If you change the value from "A" to "D" the value is never stored in the model, i.e. the model holds still "A". Thus your call to setProperty has no effect, as the internal value of the binding has never changed and setProperty does not force bindings to update in case of unchanged data.
I suggest that you obtain the binding of the input field if the button is clicked and call refresh(true). This should work (not tested).
Beside that I would suggest to use a Select control as it looks like that the available values are fixed. This would make the special logic obsolete.
Based on matbtt's answer, the following solution works without sacrifing performance:
undo for a single entry ('foo' level) triggers the following event:
oEventBus.publish("undo", "undoAll", oContext.getPath());
undo for all lines triggers the following event:
oEventBus.publish("undo", "undoAll");
attaching the following change function to each input:
var oInput = new sap.m.Input( {
value: {
path: "Qux>/foo/0/bar/0/baz",
type: new sap.ui.model.type.String(null, {
search: new RegExp("^[ABC]$")
}),
change: function(oEvent){
var that = this;
var oRegex = new RegExp("^[ABC]$");
var bTest = oRegex.test(oEvent.getParameters().newValue);
if (!bTest) {
var fnSubscribe = function(sChannelId, sEventId, oData) {
if (!oData || oData === oContext.getPath()) {
that.mBindingInfos.value.binding.refresh(true);
that.removeStyleClass("invalid-value");
oComponent.getEventBus().unsubscribe("undo", "undoAll", fnSubscribe);
}
};
oComponent.getEventBus().subscribe("undo", "undoAll", fnSubscribe);
}
}
}
});

lack of identity between jQuery selector and jQuery variable?

I'm running into a maddening problem where I set a variable to point to a jQuery selector, such as: var foobar=jQuery(this); I then pass this variable to a function to be worked on. Let's simplify a little and say the function looks like this:
function SetFieldValue (selector) {
selector.val('test');
console.log ( selector );
console.log ( jQuery('#' + selector.attr('id')) );
}
In this situation if you assume that:
the selector is always a form element (and therefore val() is a valid operation)
the selector does resolve to a single dom element which has an 'id' attribute
You would then expect the two console.log statements to output the same result, right? Well I'm running into a situation where this condition only happens about 90% of the time.
In order to give more context I've created a short screencast demonstrating the problem:
SCREENCAST LINK
For reference purposes, here's the actual SetFieldValue code that is shown in the screencast:
function SetFieldValue ( domObject, value ) {
// as a safety function, check if a string representation of the domObject was passed in and convert it to a jQuery object if it was
if ( jQuery.type(domObject) === "string") {
console.log ("Value passed into SetFieldValue was a string representation so converting to jQuery object");
domObject = jQuery(domObject);
}
if ( jQuery.inArray (domObject.prop('tagName').toLowerCase(),['input' , 'select' , 'textarea']) >= 0 ) {
console.log ("setting to value attribute: " + value);
if ( domObject.hasAttr('id') ) {
domObject.val(value);
//jQuery('#' + domObject.attr('id')).val(value);
} else {
domObject.attr('value',value);
}
console.log ("Using jQuery ID it is set to: " + jQuery('#' + domObject.attr('id')).val() );
console.log ("Using jQuery selector variable it is set to: " + domObject.val() );
} else {
console.log ("setting to html attribute");
domObject.html( value );
}
return domObject;
}
Lets examine the code a bit.
First assigning back to a parameter is not a good practice adding a var at the start of your function would be a lot better, as scope can be lost.
//Suggestion change parameter to domItem
var domObject
Your missing an error handler for when the parameter is not String.
when identifying the type use
<VARNAME>.constructor.toString().match(/function (\w*)/)[1] === "<TYPE>"
It's more efficient and handles custom types.
No need for all the logic in assignment of value attribute. Any dom Object can be made to have a value attribute. also not sure why you are setting the val versus the value.
domObject.attr('value',value);
It is at this point that I can see your code could really use some documentation to help explain purpose
If you are explicitly only wanting to set value on Input fields and set value as innerhtml on non input fields then yes the logic would be needed but could be simplified to ... as the value doesn't need to be detected to overwritten.
if (jQuery.inArray (domObject.prop('tagName').toLowerCase(), ['input' , 'select' , 'textarea']) >= 0) {
domObject.attr('value',value);
} else {
domObject.html( value );
}
No Idea why you are returning the domObject out.
So a quick rewrite without the return and keeping most of the logic adding error handling results in
/*jslint sloppy: true*/
/*global jQuery*/
function SetFieldValue(domString, value) {
// as a safety function, check if a string representation of the domObjects was passed in and convert it to a jQuery object if it was
var domObjects, index;
//errorhandling
if (domString === undefined || domString === null) {
throw {error : "domString must have a value."};
}
if (domString.constructor.toString().match(/function (\w*)/)[1] !== "string") {
if (domString.constructor.toString().match(/function (\w*)/)[1].match(/HTML[a-zA-Z]*Element/) === null) {
throw {error : "domString expected to be String or domObjects"};
}
} else {
if (jQuery(domString).length === 0) {
throw {error : "domString does not resolve to a detectable domObjects."};
}
}
//errorhandling
//action
if (domString.constructor.toString().match(/function (\w*)/)[1].match(/HTML[a-zA-Z]*Element/)) {
//made as an array to normalize as jQuery returns an array allows code to be simplified
domObjects = [domString];
} else {
domObjects = jQuery(domString);
}
//given that domObjects are an array need to step through the array
for (index = domObjects.length - 1; index >= 0; index -= 1) {
if (
jQuery.inArray(
domObjects[index].tagName.toLowerCase(),
['input', 'select', 'textarea']
) >= 0
) {
if (domObjects[index].hasAttr('id')) {
domObjects[index].val(value);
} else {
domObjects[index].attr('value', value);
}
} else {
domObjects[index].html(value);
}
}
}
The above passes JSLint
I know I didn't provide enough context for people to really dig into this problem but I have in the end solved it. What was the issue? Well it was #Kobi who first asked is the DOM element's ID unique ... to which I happily reported it was. And it had been but in fact that WAS the problem. Jesus. It's always the obvious things that you then go onto overlook that get you in trouble.
Anyway, thanks for your patience and help.

jquery string interpolation causing problems

I'm using the jquery tokeninput plugin, and I want the json token input data to be dependent upon a value that can be found somewhere in the form.
My code looks like this:
jQuery(function() {
var bparam;
if ($('#tokens')) {
bparam = $('#select_menu').val();
return $('#tokens').tokenInput(("/tokens.json?b=" + bparam)({
theme: 'facebook',
}));
}
});
So the plugin should make a request such as /tokens.json?b=124 if that value from the select_menu div was 124.
Somehow this just doesn't work and I don't know why. I'm still kindof a javascript newbie.
Any help appreciated!
if ($('#tokens')) will return an empty array ([]), so no matter what that will always evaluate to true. I'm guessing you want if ($('#tokens').length). If there is an item in the array it will evaluate to true, if it's empty it evaluates to false.
What's tripping you up is when the variable is being set. bparam is being set on page load. I would bind it to be set when whatever is triggering the event occurs.
Apart from the length > 0 call I had to make (thanks for pointing that out Stuart Nelson and Shusl!), it turned out that the string interpolation in coffeescript somehow wasn't working as I wanted. The same code translated into javascript did actually work.
Coffeescript was being translated into:
jQuery(function() {
var bparam;
if ($('#tokens').length > 0) {
bparam = $('#select_menu').val();
return $('#tokens').tokenInput(("/tokens.json?b=" + bparam)({
theme: 'facebook',
}));
}
});
Now, the working code is, directly written in javascript/jquery ,is:
jQuery(function() {
if ($("#tokens").length > 0) {
var bparam
bparam = $('#select_menu').val();
return $('#tokens').tokenInput("/tokens.json?b=" + bparam, {
theme: 'facebook',
});
}
});
Note these extra parenthesis in
(("/tokens.json?b=" + bparam)
whereas
("/tokens.json?b=" + bparam
is the working solution.

Javascript - Overriding property (not methods) inside an Object

Let us explain the question with an example. I have a text box. The textbox (every textbox) has a property called 'value'. I want to over ride that textbox.value and comeup with and
new thing. When the text in textbox is 'ranjan' then the textbox.VALUE property returns 'ranjan'. Now I want to thus overwrite this so that when you type textbox.VALUE you get a different thing say for example, RaNjAn or say, Mr. Ranjan or whatever.
We can over ride methods using Object.PROTOTYPE property. But how can we do it for non-function objects inside object for example the 'value' property in this case.
If i need to make the question more clear, please mention.
Regards - Ranjan.
You can define custom properties for your element using Object.defineProperty
If you have a case where you need to get the value of an element as Mr. <value> for example, then this approach will be useful. Overriding standard properties may not be such a good idea.
Demo: http://jsfiddle.net/zvCGw/2/
Code:
var foo = document.getElementById('foo');
Object.defineProperty(foo, "xvalue", {
get: function() {
return 'Mr. ' + foo.value;
},
set: function(_newValue) {
foo.value = _newValue;
}
});
foo.xvalue = 'Hello';
alert(foo.xvalue);
What you are trying to do is called type augmentation. In javscript there are types of things, such as the object type, array type, etc.
You can use the prototype to augment these built in types, for example, adding a new method that can be called on any object that is of the type array:
Array.prototype.myNewMethod = function() {
//the method logic
}
Then you can call your method on any array:
[0,1,2].myNewMethod();
There is no INPUT type in JavaScript, DOM elements are classed as Objects. But you could jerry-rig something together that kind of does what you need, like this
Object.prototype.changeValue = function(el) {
if (el.tagName === "INPUT") {
return "Mr " + el.value;
}
}
var testEl = document.getElementById("test");
document.write(testEl.changeValue(testEl))
Used in conjunction with this textbox:
<input id="test" value="Dan" />
You would then get the output 'Mr Dan'
However, this is not great, it's just to illustrate the point and is just something to get you started...
I made a fiddle so you can play around with it
You can redeclare value but it will do no good ;)
This example would do that if test is a textbox
var input = document.getElementById("test");
Object.defineProperty(input, "value", {
get : function () {
return "'" + this["value"] + "'";
},
set : function (val) {
this["value"] = val;
}
});
input.value = "Hello World";
alert(input.value);
Unfortunately, "this.value" will reference the getter causing infinite recursion.
Once redefined, the original value will no longer exist so you will have crippled the element object.
At least as far as I have been able to test.
If the property you're trying to override can also be represented by an HTML attribute (e.g. an input's value), then you can use getAttribute and setAttribute.
Object.defineProperty(myInputElement, 'value', {
get: function () {
return myInputElement.getAttribute('value');
},
set: function (value) {
myInputElement.setAttribute('value', value);
}
});
Note, however, that this override itself cannot be overridden without re-implementing it.

Why my JQuery doesn't load on IE?

I did this javascript quiz : http://utbm.trunat.fr/CIP/quiz/
It works on normal browser but doesn't even load with Internet Explorer.
It seams that it doesn't recognize the initQuiz() function.
Do you have any idea of how I can fix this ?
Internet Explorer doesn't accept the trailing comma:
question = {'texte': $(this).attr("texte"),
'sound': $(this).attr("sound"),}
Apparently, another error comes from this line:
$('title').html(QUIZ_TITLE[lang]);
Turns out you can't set the title like that in IE. Use document.title = QUIZ_TITLE[lang] instead.
A third error is that you're introducing a new variable, question without the var keyword, which is an error in IE. You're doing it again, later on, in response. Update your loadXML as such:
function loadXML(xml) {
$(xml).find("question").each(function() {
var question = {'texte': $(this).attr("texte"), 'sound': $(this).attr("sound")};
reponses = [];
$(this).find('carre').find('reponse').each(function() {
var reponse = {'texte': $(this).text(), 'sound': $(this).attr("sound"), 'bonne': false};
if($(this).attr('bonne') == "vrai") reponse['bonne'] = true;
reponses.push(reponse);
});
question['reponses'] = reponses;
questions.push(question);
});
startGame(questions);
}
A fourth error is in the way you're verifying that an answer is correct.
if($(this).attr('data-type') == 'true')
You compare the value of the data-type attribute to the string value "true", but when you assign the value, you set it to the boolean value true:
$('#r'+(i+1)+'input').attr('data-type', r.bonne);
To make sure that you're always comparing string values, for instance, you could set the value as such:
$('#r'+(i+1)+'input').attr('data-type', r.bonne.toString());

Categories

Resources