How to let ng-model not update immediately? - binding

Code:
<input type="text" ng-modal="name" />
{{name}}
When I input something into the input, the following {{name}} will change immediately. Is it able to configure it only update the name after I input all characters and leave the input?

This is about recent additions to AngularJS, to serve as future answer.
Angular newer versions (now in 1.3 beta), AngularJS natively supports this option, using ngModelOptions, like
ng-model-options="{ updateOn: 'default blur', debounce: { default: 500, blur: 0 } }"
NgModelOptions docs
Example:
<input type="text" name="username"
ng-model="user.name"
ng-model-options="{updateOn: 'default blur', debounce: {default: 500, blur: 0} }" />

Update
As many have mentioned Angular now has built-in support for this using the ng-model-options directive. See more here.
<input type="text" ng-model="name" ng-model-options="{updateOn: 'blur'}" />
Old answer below:
There's no built-in option for ng-model to change that behaviour, but you can write a custom directive doing it. #Gloopy wrote a directive like that for another question. You can look at the fiddle here.
The directive unregisters from the input and keydown events which trigger the update after each keystroke.
<input type="text" ng-model="name" ng-model-onblur />
Update:
Updated fiddle to use latest stable AngularJS (1.2.16 as of writing), instead of directly referencing the master version at github.
Also added an explicit priority so that the directive is run after ng-model to ensure event listeners are changed correctly.

A better option is to use the ng-model-options:
<input type="text" ng-model="name" ng-model-options="{updateOn: 'blur'}" />

Working directive code(ng-1.2RC3):
use:
ng-model-onblur
.directive('ngModelOnblur', function () {
return {
restrict: 'A',
require: 'ngModel',
priority: 1,
link: function (scope, element, attrs, ngModelCtrl) {
if (attrs.type === 'radio' || attrs.type === 'checkbox') { return; }
var update = function () {
scope.$apply(function () {
ngModelCtrl.$setViewValue(element.val().trim());
ngModelCtrl.$render();
});
};
element.off('input').off('keydown').off('change').on('focus', function () {
scope.$apply(function () {
ngModelCtrl.$setPristine();
});
}).on('blur', update).on('keydown', function (e) {
if (e.keyCode === 13) {
update();
}
});
}
};
})

Related

jQuery UI tooltip on pseudo disabled elements

I would like to show a tooltip on a text input that has a ui-state-disabled class.
I took a peek to the tooltip source code and I couldn't find something that checks against that particular class. So I don't know why it won't show.
As far as I can tell, the elements aren't disabled per se, they just have a class applied to them.
So, how can I show a tooltip on elements that have that class? I don't want to use a wrapper or anything like that. Maybe extending through widget factory...
Here's a sample code
HTML
<input name="#1" class="text" data-tooltip="message A">
<input name="#2" class="text" data-tooltip="message B">
<br>
<button id="disable">disable input #2</button>
<button id="enable">enable input #2</button>
JS
$(".text").each(function()
{
$(this).tooltip({
content: $(this).data("tooltip"),
items: ".text"
});
});
$("#disable").click(function()
{
$("input[name='#2']").addClass("ui-state-disabled");
});
$("#enable").click(function()
{
$("input[name='#2']").removeClass("ui-state-disabled");
});
FIDDLE: https://jsfiddle.net/hn1o4qs2/
See the doc (http://api.jqueryui.com/tooltip/):
In general, disabled elements do not trigger any DOM events.
Therefore, it is not possible to properly control tooltips for
disabled elements, since we need to listen to events to determine when
to show and hide the tooltip. As a result, jQuery UI does not
guarantee any level of support for tooltips attached to disabled
elements. Unfortunately, this means that if you require tooltips on
disabled elements, you may end up with a mixture of native tooltips
and jQuery UI tooltips.
Solution with wrapper
Your HTML:
<span class="input-container" data-tooltip="message A">
<input name="#1" class="text">
</span>
<span class="input-container" data-tooltip="message B">
<input name="#2" class="text">
</span>
<br>
<button id="disable">
disable input #2
</button>
<button id="enable">
enable input #2
</button>
Your Javascript
$(".input-container").each(function()
{
$(this).tooltip({
content: $(this).data("tooltip"),
items: ".input-container"
});
});
// ... The rest is the same
Solution with fake disabled-property
Here you can use a readonly attribute and a custom class for disabled input.
Playground: https://jsfiddle.net/5gkx8qec/
As I've stated in my question, I needed to get this working without adding a container or anything like that. And I was willing to extend the widget somehow...
So I read the source code more carefully and searched throught the whole repository for ui-state-disabled, and found that in widget.js there is an _on() method that at some point performs a check against that class and a flag called suppressDisabledCheck
A comment in code says
// Allow widgets to customize the disabled handling
// - disabled as an array instead of boolean
// - disabled class as method for disabling individual parts
This was very important, it gave me the clue that this check could be overriden. So a quick search in google and the widget factory had the answer:
Automatically handles disabled widgets: If the widget is disabled or
the event occurs on an element with the ui-state-disabled class, the
event handler is not invoked. Can be overridden with the
suppressDisabledCheck parameter.
So basically I did this:
$.widget("ui.tooltip", $.ui.tooltip,
{
options: {
allowOnDisabled: false
},
_on: function()
{
var instance = this;
this._super(instance.options.allowOnDisabled, {
mouseover: "open",
focusin: "open",
mouseleave: "close",
focusout: "close"
});
}
});
And then used it like this:
$(".text").each(function()
{
$(this).tooltip({
allowOnDisabled: true,
content: $(this).data("tooltip"),
items: ".text"
});
});
EDIT 2022-09-15
I was having some trouble with this implementation, so I've changed it a little bit
$.widget("ui.tooltip", $.ui.tooltip,
{
options: {
allowOnDisabled: false
},
_create: function()
{
this._super();
var instance = this;
this._on(instance.options.allowOnDisabled, {
mouseover: "open",
focusin: "open",
mouseleave: "close",
focusout: "close"
});
}
});

.validate() not working in jQuery Mobile

It is my first time using the plugin and .validate() method. Now I have a form and every time I click the submit button it runs with out doing the form validation. Here is my code:
<form class="form d" method="post" action="">
<input type="text" name="searchtitle" id="searchtitle" placeholder="Enter the textbook's title">
<input type="text" name="searchauthor" id="searchauthor" placeholder="Enter the textbook's author">
<input type="text" name="searchpublisher" id="searchpublisher" placeholder="Enter the textbook's Publisher">
<input type="text" name="searchedition" id="searchedition" placeholder="Enter the textbook's edition">
<select name="searchuniversity" id="searchuniversity"></select>
<select name="searchuniversitycampus" id="searchuniversitycampus" ></select>
<input type="submit" id ="searchsubmit" name="searchsubmit" value="Search">
</form>
I then have the following Javascript:
$(document).on('pageinit',"#searchpage",
//this funciton will carry out the things we need to do to carry out our search
function(e)
{
e.preventDefault();
$(".form.d").validate({
rules: {
name: {
required: true
},
email: {
required: true,
email: true
},
comments: {
required: true,
minlength: 5,
nourl: true
}
},
messages: {
name: "Required Field",
email: "Valid Email Required",
comments: "Required Field + No URL's"
}
});
$("#searchsubmit").click(
function(e)
{
//Do a lot of processing here
});
});
Like I said I'm very new to doing the forma validation and using the function.
Here is a jsFiddle of the problem. When you click on submit in the fiddle it alerts "hello" and then it does the validation. How to stop this from happening. i.e validate first 1st and then run the function?
Your whole problem is your click handler. The plugin already has callback functions built in that will capture the click event of the submit button. Use the submitHandler to fire a function when the form is valid. Use the invalidHandler to fire a function when the form is invalid.
You already have the submitHandler callback in your jsFiddle so I refactored your jsFiddle code as follows:
$(document).on('pageinit', function(){
$('#myform').validate({ // initialize the plugin
rules: {
field1: {
required: true
},
field2: {
required: true
}
},
submitHandler: function (form) {
alert("hello"); // stuff to do when form is valid
alert('valid form submitted'); // for demo
return false;
},
invalidHandler: function () {
// stuff to do when form is invalid
alert("invalid form"); // for demo
}
});
// remove click handler
// use the plugin's built-in callback functions instead
//$("#test").click(function(){alert("hello")});
});
DEMO: http://jsfiddle.net/BTwaP/1/
See documentation for all callback functions
EDIT:
As of jQuery Mobile version 1.4, the pageinit event has been deprecated and replaced with pagecreate.
Good Reference: https://stackoverflow.com/a/14469041/594235

angular directive compile order

I was trying to write a simple directive to generate a (potentially) more complex dom element. I am quite confused about what is going on here but I think the directive I use inside my directive get linked first? Anyway the element I am generating is not visible where it should.
Sorry for all that confusion, here is the plunkr:
http://plnkr.co/edit/vWxTmA1tQ2rz6Z9dJyU9?p=preview
I think the directive I use inside my directive get linked first?
Yes. A child directive's link function will execute before the parent's link function.
Here is a fiddle that shows two nested directives,
<div d1>
<div d2></div>
</div>
and it logs when the directives' controller and link functions are called.
There are a few issues with your Plunker:
Since you are using # for your isolate scopes, you need to use {{}}s in your attribute values:
<visible value='{{visible}}'>plop</visible>
<invisible value='{{visible}}'>plop</invisible>
Since $scope.visible is defined in your controller, I assume you meant to use that value, and not test.
In the invisible directive, you need to use isolate scope property value in your link function. Property visible is available to the transcluded scope (which is in affect if you use a template in your directive like #Langdon has) but not the isolate scope, which is what the link function sees.
var template = "<span ng-show='value'>{{value}}</span>";
Plunker.
If you want a simple directive, you're better off letting Angular do most of the work through ngTransclude, and $watch.
http://plnkr.co/edit/xYTNIUKYuHWhTrK80qKJ?p=preview
HTML:
<!doctype html>
<html ng-app="app">
<head>
<meta charset="utf-8">
<title>trying to compile stuff</title>
<script src="http://code.angularjs.org/1.1.1/angular.js"></script>
<script src="app.js"></script>
</head>
<body>
<div ng-controller="AppCtrl">
<input type="checkbox" ng-model="test" id="test" /><label for="test">Visibility (currently {{test}})</label>
<br />
<br />
<visible value='test'>visible tag</visible>
<invisible value='test'>invisible tag</invisible>
</div>
</body>
</html>
JavaScript:
angular
.module('app', [])
.controller('AppCtrl', function($scope) {
$scope.test = false;
})
.directive('visible', function() {
return {
restrict: 'E',
transclude: true,
template: '<span ng-transclude></span>',
replace: true,
scope: {
value: '='
},
link: function(scope, element, attrs) {
console.log(attrs);
scope.$watch('value', function (value) {
element.css('display', value ? '' : 'none');
});
console.log(attrs.value);
}
};
})
.directive('invisible', function() {
return {
restrict: 'E',
transclude: true,
template: '<span ng-transclude></span>',
replace: true,
scope: {
value: '='
},
link: function(scope, element, attrs) {
scope.$watch('value', function (value) {
element.css('display', value ? 'none' : '');
});
}
};
});

how to make datetimepicker readonly in struts 2 compatible with ie7

I'm using the Dojo Struts2 datetimepicker, But textfield is editable with the keyboard. I want it in readonly.
I know that this question is answered on another thread, but the solution isn't compatible with ie7, wich is required for me.
The solution in the another thread is:
window.onload = function() {
document.getElementsByName("dojo.test")[0].setAttribute("readOnly","true");
}
But, when I try that on IE7, I get a javascript error:
'document.getElementsByName(...).0' is null or not an object
I read about that, and chage it to:
'document.getElementsBy**Id**(...).0'
But I get another error: The object doesn't support that property.
Any suggestions?
I just wondering if I could change the template of the datetimepicker as I did with a simple Struts2 template... That will solve the problem
<script type="text/javascript">
$(document).ready(function() {
makeReadonly();
});
function makeReadonly() {
setTimeout(function () {
$(".calendar").attr('readonly', 'readonly');
}, 1000);
}
</script>
<td>
<sx:datetimepicker name="up_bod" displayFormat="yyyy-MM-dd" cssClass="rounded calendar" >
</sx:datetimepicker>
</td>
Nice Question.
Use following script. This will work in all browsers.
< % # taglib prefix="sd" uri="/struts-dojo-tags" % >
<head>
<sd:head/>
</head>
< script type="text/javascript">
window.onload = function() {
document.getElementById('fromDate').children[1].setAttribute("readOnly","true");
};
</ script>
<sd:datetimepicker name="fromDate" id="fromDate" label="From Date" />
I hope this will work for you.

Display errors in tooltips jquery plugin based on asp.net mvc validation attributes

I want to display jquery errors in tooltips like in this image:
there is some jquery plugins around which could do that:
http://www.position-relative.net/creation/formValidator/demos/demoValidators.html
http://validity.thatscaptaintoyou.com/
But they not designed to work with asp.net mvc 3.0 validation attributes.
Is there any similar plugin which would do the thing? or any thing else i can do to display errors like that in tooltips?
We have done something similar to this using Jquery validation plugin. For this we have to create the popup div initially.
Javascript Fn
$("#formID").validate({
submitHandler: function (form) {
CallFunction();
},
highlight: function (element, errorClass) {
HidePopup(element);
ShowPopup(element);
},
unhighlight: function (element, errorClass) {
HidePopup(element);
},
errorElement: "span",
errorPlacement: function (error, element) {
error.appendTo(element.prev("label"));
},
rules: {
txtName:"required"
}
});
function ShowPopup(paramElement)
{
//function to show popup and position div accordingly
$('#div'+paramElement.Id).show();
}
function HidePopup(paramElement)
{
//function to hide popup
$('#div'+paramElement.Id).hide();
}
**Html**
<form id="formID" action="">
<input name="txtName" type="text" id="txtName" />
<div id="divtxtName" >Please enter name</div>
</form>

Resources