I have expected that order for atributes in elements can be changed despite the order in html (only FF 43.0.1). Example:
<input type="checkbox" data-type="can-be-also-empty"/>
Please, run snippet in Chrome an then in FF.
Result from devtools:
<input data-type="can-be-also-empty" type="checkbox"/> - FF
<input type="checkbox" data-type="can-be-also-empty"/> - Chrome
This can be affected with using angular. Custom directives guide
Angular normalizes an element's tag and attribute name to determine which elements match which directives
The normalization process is as follows: Strip x- and data- from the front of the element/attributes.
Thats why i think, if data-type atributes going first in element, angular stripping data- and it affecting type="checkbox" to type="can-be-also-empty".
Next snippet can show better, what i mean:
angular.module('app', []).directive('example', function(){
return {
template: '<input type="checkbox" data-type="eny-value" ng-model="value"/><p>{{value}}</p>',
restrict: 'E',
link: function($scope){
$scope.value = false;
}
}
})
<!DOCTYPE html>
<html ng-app='app'>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title></title>
</head>
<body>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.0/angular.js"></script>
<example></example>
</body>
</html>
Also try to run it in FF and Chrome, expression will not be evalueted in FF.
Next step, to move data-type="eny-value" before type. Now it is not working in any browser.
The problem comes from how AngularJS matches directives. In this particular case, it's about input[checkbox] it's matches comes from the type attribute. According to AngularJS docs for directives, it can be matched from both type and data-type, so when angular normalize the data-type, depending on the order of the attributes, it overides de previous value (aka checkbox).
This behaviour causes input[checkbox] to never work as expected, so then ngModel never receives a value of the checked field.
The best approach is to not use such thing, don't use attributes that matches with angularjs normalization.
Related
A call to numericInput(), like this:
numericInput("obs", "Observations:", 10, min = 1, max = 100)
constructs HTML code like this:
<div class="form-group shiny-input-container">
<label for="obs">Observations:</label>
<input id="obs" type="number" class="form-control" value="10" min="1" max="100"/>
</div>
Then, presumably, in the browser, JavaScript code provided by one of the scripts included in the HTML doc's header finds that <input> element and renders it with the interactive widget displayed below:
I'm having a hard time, though, figuring out where the code that finds that <input> element and then triggers production of the corresponding widget is stored. Is it in Shiny's own JavaScript, or in that borrowed from by Bootstrap or jQuery UI or one of the other plugins that ship with shiny?
My question(s):
Where is the JavaScript code that provides the widget pictured above and associates it with the HTML <input> element? And how, from the code that's involved, might I have learned that on my own?
More only possibly useful details
This section of the script "shiny.js" finds the <input> element of interest, and provides methods that can get and set the widget's value. It doesn't (as far as I can see) provide the widget itself.
var numberInputBinding = {};
$.extend(numberInputBinding, textInputBinding, {
find: function(scope) {
return $(scope).find('input[type="number"]');
},
getValue: function(el) {
var numberVal = $(el).val();
if (/^\s*$/.test(numberVal)) // Return null if all whitespace
return null;
else if (!isNaN(numberVal)) // If valid Javascript number string, coerce to number
return +numberVal;
else
return numberVal; // If other string like "1e6", send it unchanged
},
setValue: function(el, value) {
el.value = value;
[... snip ...]
}
});
inputBindings.register(numberInputBinding, 'shiny.numberInput');
And here is a copy of the <head> section of the the shiny-generated HTML file that results in the numericInput widget. The scripts it references can mostly be found here
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="application/shiny-singletons"></script>
<script type="application/html-dependencies">json2[2014.02.04];jquery[1.11.0];shiny[0.12.2];bootstrap[3.3.1]</script>
<script src="shared/json2-min.js"></script>
<script src="shared/jquery.min.js"></script>
<link href="shared/shiny.css" rel="stylesheet" />
<script src="shared/shiny.min.js"></script>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link href="shared/bootstrap/css/bootstrap.min.css" rel="stylesheet" />
<script src="shared/bootstrap/js/bootstrap.min.js"></script>
<script src="shared/bootstrap/shim/html5shiv.min.js"></script>
<script src="shared/bootstrap/shim/respond.min.js"></script>
<title>Hello Shiny!</title>
</head>
Here's the incorrect assumption that made this so hard for me to figure out:
Then, presumably, in the browser, JavaScript code provided
by one of the scripts included in the HTML doc's header finds that
element and renders it with the interactive widget displayed
below:
In fact, as #epascarello points out, modern browsers themselves support <input type="number">.
(For further documentation of this fact, along with a long list of the features whose support was enabled by the incorporation of JavaScript in these modern web browsers, see Chapter 4 of "HTML for Web Designers".)
There is a way to get the input that binding a model's property.
I want to do this to blur the search input after I send the form,
and I want to do this dynamically for later changes in html source.
Example:
var app = angular.module("MyApp", []);
app.controller('ctrl', function($scope) {
$scope.term = 'test';
$scope.submit = function(){
document.querySelector('#search').blur();
// I want replace document.querySelector('#search') with something like 'getElementByProp($scope.term)'
};
});
<!DOCTYPE html>
<html data-ng-app="MyApp">
<head>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<meta charset="utf-8">
<title>JS Bin</title>
</head>
<body>
<div data-ng-controller="ctrl">
<form data-ng-submit="submit()">
<input id="search" type="search" data-ng-model="term" />
</form>
</div>
</body>
</html>
There's a fundamental error in your intention here.
Please keep the following always in mind:
The controller should know absolutely nothing about the DOM
This is a precious rule of thumb that will help you a lot.
Now, of course you need to interact with the DOM from your javascript (AngularJS code), and for that you should use Directives.
In your case though I would use another approach:
if (document.activeElement) {
document.activeElement.blur();
}
This will work for any focused elements and you won't need to specifically query any DOM element.
So in theory you're not giving the controller any knowledge about the DOM, so for me this doesn't break the rule I mentioned above.
Just as a side note, $document for some reaon doesn't expose this activeElement.
I don't have time to dig into the code to see why but as far as I've tested you need to stick with the native document object.
An easy way to do this is using the jQuery little version that comes with AngularJS.
Try this:
var element = angular.element('[ng-model="YOUR_MODEL_NAME_HERE"]');
element.blur(); // element is a jQuery object
This should work
The reason this is not possible is that this is not something you'll usually want to do in Angular - you're most likely still "thinking like you're using jQuery". Please elaborate on why you want to manipulate the DOM yourself in the first place. Most likely it's a different problem that you can solve with e.g. a directive.
(This may sound like a lame answer, but "don't do this" very likely is the only correct way to handle this situation.)
I have a simple select element that I am trying to enforce a value being present to submit the form and I have tried both setting the required attribute as well as using ng-init to ensure there is a value selected and both fail.
I am using ng-options to create a list of values from an array of Objects that have a ref property. Then I would like to use ng-init to set the shown value to the first Object.ref in the array.
<select name="refmarker" class="input-block-level form-width-adjust" ng-model="model.refmarker" ng-options="rm.ref for rm in refmarkers" ng-disabled="editable" ng-init="model.refmarker='refmarkers[0].ref'" required></select>
I have tried the following without any luck
ng-init="model.refmarker='refmarkers[0]'"
ng-init="model.refmarker='refmarkers[0].ref'"
ng-init="model.refmarker='rm.ref'"
Also the required attribute doesn't work ? Is the angular select element buggy or am I doing something wrong?
required will only work in side a form element.
What you want is ng-init="model.refmarker=refmarkers[0]"
<!doctype html>
<html lang="en" data-ng-app="app">
<head>
<meta charset="utf-8">
<title>Test</title>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.6/angular.js"></script>
<script type="text/javascript">
angular.module('app',[])
.controller('Main',function($scope)
{
$scope.model = {};
$scope.refmarkers = [{ref:'abc'},{ref:'def'},{ref:'ghi'}];
});
</script>
</head>
<body ng-controller="Main">
{{'Angular'}}
<select ng-model="model.refmarker" ng-options="rm.ref for rm in refmarkers" ng-init="model.refmarker=refmarkers[0]"></select>
{{model.refmarker}}
</body>
</html>
I'm working on some code that uses custom attributes on DOM nodes. These are necessary for particular logic that is used. The custom attributes are set on input elements such as dropdowns and text input fields and are of the format...
<input type="text" myCustomId="blah"...
This all works fine with standard HTML inputs. However, we are looking to use some Dijit widgets in place of the standard inputs to achieve a specific look & feel.
The DOM is parsed onLoad and the widgets are loaded (we set data-dojo-type to specify the widget).
The problem is Dojo/Dijit doesn't preserve the custom attributes. They get lost in the parsing.
Is it possible to specify custom attributes that a Dijit widget should use?
Edit:
Heres some sample HTML that highlights the problem. The "custom" attribute is being lost...
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="http://dojotoolkit.org/reference-guide/1.9/_static/js/dijit/themes/claro/claro.css">
<script>dojoConfig = {parseOnLoad: true}</script>
<script src="http://dojotoolkit.org/reference-guide/1.9/_static/js/dojo/dojo.js"> </script>
<script>require(["dojo/parser", "dijit/form/TextBox"]);</script>
</head>
<body class="claro">
<label for="firstname">Test: </label>
<input type="text" name="firstname" custom="test" value="testing testing"
data-dojo-type="dijit/form/TextBox"
data-dojo-props="trim:true, propercase:true" id="firstname" />
</body>
</html>
I found a solution based on this article...
http://dojotoolkit.org/features/1.6/html5data-attributes
Essentially if I add "data-" in front of our custom attributes, the dojo parser preserves the custom attribute in the widget. It doesn't place the attribute on the top most node of the widget but it does enough for us to look it up
Try use data-dojo-props='urCustomID=XXX', then you could obtain it by get("urCustomID").
the custom attributes added are retained by the widgets indeed. But, they are case-insensitive. According to the example you provided in your question, try accessing it by,
registry.byId('field_id').get('mycustomid')
or
dijit.byId('field_id').get('mycustomid')
Let me give a simple example:-
<script type='text/javascript'>
dojo.require("dijit.form.TextBox");
function func() {
alert(dijit.byId('namefld').get('customid'));
}
</script>
</head>
<body class="claro">
<input type="text" customId='mango' dojoType="dijit.form.TextBox" id="namefld" name="namefld"/>
<button onclick='func()'>click</button>
</body>
I am trying to attach a click event to a check box using JavaScript. Shown below is the HTML and JS.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title></title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<input type="hidden" name="caution_c" value="0">
<input type="checkbox" id="caution_c" name="caution_c" value="1" tabindex="120">
<script type="text/javascript">
var cb = document.getElementById('caution_c');
cb.onclick = function() {
alert(1);
}
</script>
</body>
</html>
The problem is that in IE, the click event does not fire. I have narrowed down the problem location. The issue is that there is a hidden input just before the check box and both these elements have the same name. I'm not sure why this is causing a problem(after all, I'm using getElementById and the hidden element does not even have an id).
Is there a valid reason for this type of behavior (IE only. Works fine in Firefox...as always :( )? Also, is there a good workaround (I could just do document.getElementsByName('caution_c')[1] but I don't want to...)
Internet Explorer gets confused over name and id - it is highly recommended to treat these two attributes as if they were the same.
You can fix it either by 1) ensure that there are no id/name conflicts in your document, or 2) override IE's native getElementById-method.
Read more about it here.
Try using a different event such as onchange or onfocus to see if that solves it. Also I don't think onclick will be fired if a user tabs onto the checkbox, which may or not be how you intend it to work.
I agree, IE is poor in understanding things at html level.
I would rather add the link to button rather than using anchor elements, as IE is having trouble at anchor level with document.getElementById(). Try same at button and will work for other users.