Hoping to re-create some of the functionality that's available to us in Angular 1.3.X -- the app I am creating has to work well (or at least well-enough) in IE 8. For that reason, I am (sadly) constrained to not using 1.3.X. I've been running into some trouble trying to emulate the $ng-touched attr that is available in 1.3.X.
One part of our app needs to alert users that their form element is invalid if they've tab-bed through it. As it stands, it doesn't set the $invalid attr on any form elements unless I've entered in text and deleted it. I tried using $pristine and $dirty to achieve $invalid after tabbing through, but they both seem to act based on the input's value, not whether it's been touched (maybe this was one of the big advantages of 1.3.X)
Goal: when a user tabs through a form, validations can be fired and set each empty form element as $invalid if it's blank. Basically to emulate the behavior of the $ng-touched attr in 1.2.X. Here's what I have so far:
angular.module('goodStewardApp')
.directive('chf-validate', function () {
return {
require: 'ngModel',
link: function(scope, elm, attrs, ctrl) {
$(elm).blur(
function(elm) {
ctrl.$setValidity(elm, false);
}
);
}
};
});
Any help would be greatly appreciated. Thanks!
Turns out the best way to accomplish emulating the behavior of ng-touched in angular 1.2.x is to use ngBlur to set a validation attribute to be true. So:
<form name="aForm">
<input name="foo" ng-model="foo.bar" ng-blur="validateThisElement=true" ng-required="true">
<div ng-show="aForm.foo.$error.required && validateThisElement">
Oh no! An alert!
</div>
</form>
This allows you to run a validation after a user tabs through your form, a common way that people used to using computers will use to interact with your angular form/app. Hope this helps anyone still stuck w/ 1.2.X for IE8 reasons!
Related
I have the following code, which results in a single password input being rendered with the toggler overlaying the visible input. The ion-toggle directive toggles visibility of the two inputs.
<label class="item item-input">
<input placeholder="Password" ng-hide="showPassword" type="password">
<input placeholder="Password" ng-if="showPassword" type="text">
<ion-toggle ng-model="showPassword" toggle-class="toggle-energized"> </ion-toggle>
</label>
When the toggler has focus, the software keyboard retracts. The user has to then tap back into the input to show the keyboard again.
How can I programmatically show/retain the keyboard when the toggler has focus? I've tried writing a directive to force focus back onto the inputs, but that feels clunky, and there's the issue of there being two inputs.
Here's a basic demo. You won't get a keyboard in a desktop browser, of course.
Thank you.
I created a directive which will give focus on password field when toogle button is clicked. Also refactored html of password field instead of two field it will only show one field.
Markup
<ion-content>
<label class="item item-input" ng-init="pwd">
<input placeholder="Password" ng-attr-type="{{showPassword? 'text': 'password'}}"
ng-model="pwd" do-focus="showPassword"/>
<ion-toggle ng-model="showPassword" toggle-class="toggle-energized"> </ion-toggle>
</label>
</ion-content>
Directive
.directive('doFocus', function(){
return{
link: function(scope, element, attrs){
scope.$watch(attrs.doFocus,function(newValue, oldValue){
element.focus();
});
}
}
});
Forked Codepen
Edit
Directive has implemented in such a way that we are passing to toggling flag name to the showPassword inside directive attribute like do-focus="showPassword" so that directive will put $watch on the scope variable by using attrs.doFocus, watcher function gets fired and when you toggle the showPassword button. Basically this inner watcher is scope.$watch('showPassword'. Then the function first parameter would be newValue which is changed value & oldValue means the previous value of showPassword model. Here in your case newValue & oldValue are just redundant they are just not use anywhere, but if you wanted to do something on there change then they could help you.
The cordova keyboard plugin can close the native keyboard but not open it (it can open it on android but not ios). This is a interesting problem sometimes with multiple inputs (mostly on ios) I will have the keyboard close and then reopen. If you only need android you can use this plugin to open the keyboard when the toggle is taped using on-tap="foo()", however as far as I know as of now there is now other way to interact with native keyboard or keyboard events. Unless on toggle tap force focus back to the password input, but like you said that is not ideal: give the plugin a try, maybe you can get it working on both platforms.
Keyboard Plug-in: https://github.com/driftyco/ionic-plugin-keyboard
I am wondering if the following is possible:
<directiveName parameter1=value1 parameter2=value2 ng-disabled="true"> </directiveName>
For some reason, it wasn't working for me and I wasn't able to find much examples of a use like this.
I can, however, toggle the visibility of the directive using this:
<directiveName parameter1=value1 parameter2=value2 ng-if="true"> </directiveName>
Why can't I seem to use ng-disabled?
(The purpose of the directive is to make a connection with a topic and display the messages in the topic, so all it outputs is plain text.)
As per the documentation for ngDisabled:
This directive sets the disabled attribute on the element if the
expression inside ngDisabled evaluates to truthy.
But in your case, it seems ngDisabled will be adding a disabled attribute to an element that does nothing with it.
'disabled' only makes logical sense for elements that allow user input or interaction. Out of the box, it works for form inputs, anchor tags and buttons. If you require 'disabled' behaviour for other things then you need to provide it yourself.
I am currently working on an angularJS application. I have an HTML form with around 40 controls. All other controls are rendering fine except the select fields. There are around 16 select fields on my page, and this select fields is an angular directive. When I say select field is not rendering fine, I mean it loads however it first stretches to a bigger size and then comes to it's size specified in CSS. Hence the rendering is not smooth. Any particular reason why my select fields are stretching and then comes to a normal size? Thanks for the help in advance.
The possible reason I see why this happens is that the browser loads your select elements before it finishes loading your css files or angularjs file. Please try declaring the width of the select field using inline css on your directive template.
<select style="width:100px"><option>Option 1</option></select>
Another solution that you may try is using the "elem" parameter in your directive declaration.
app.directive('test', function() {
return {
restrict: 'AE',
replace: true,
templateUrl: '<select><option>Option 1</option></select>',
link: function(scope, elem, attrs) {
elem.css('width', '100px');
}
};
});
Hope this helps! :)
This happens due to slower response from database. All 16 drop down data coming from DB correct. You can optimized your angular script.
I currently use markup like this for all my ng-messages
<div ng-messages="myForm.fieldName.$error && (myForm.firldName.$dirty || myForm.$submitted)">
<div ng-message="required">This field is required</div>
<div ng-message="minlength">Your field is too short</div>
</div>
It's a bit messy though and I'd like to somehow override or extend ng-messages so that it automatically checks to see whether the field is dirty or the form that the field is nested inside (by walking up the DOM maybe?) is $submitted.
I'd like this to be the default behaviour on all ng-messages in my site and can't forsee a situation when I'd need to show error messages when the input hadn't been used and the form hadn't been submitted so I think it's safe to override that behaviour, I just don't know how to do it.
I know I can replace the ng-messages entirely but then I'd have to recreate all of the default behaviours of that directive and these might change in future angular versions so I'd rather just extend it if possible. I don't know whether Angular provides any hooks for this (I've vaguely heard of decorator methods?) or whether to make a sibling directive, something like "ng-custom-messages" which just hides the element if the conditions aren't met?
So, I have a couple of ideas but I need a bit of a nudge to show how to implement them, just a bit of skeleton code if anybody is feeling charitable?
The answer to this was unfortunately to write a new form directive which automaticalley set all fields to dirty when submission happens.
Here is a short snippet of code...
angular.forEach( formCtrl , function ( formElement , fieldName ) {
if ( fieldName[0] === '$' ){
return;
}
formElement.$setDirty();
}, this);
formCtrl.$setDirty();
scope.$apply();
I recommend instead using an ngIf on the element that uses the ngMessages. Note that ngMessages accepts the $error property of NgModelController (or FormController).
<div ng-if="myForm.fieldName.$invalid && (myForm.fieldName.$dirty || myForm.$submitted)"
ng-messages="myForm.fieldName.$error">
<div ng-message="required">This field is required</div>
<div ng-message="minlength">Your field is too short</div>
</div>
As an aside, you may find it more appropriate to use $touched instead of $dirty in order to postpone error feedback until the element has lost focus (or the form has been submitted).
What I'm trying to achieve is that when user clicks on the input field, I would like the search bar to be on top of the page. I'm using hasFocus but it only works the first time the page is loaded after I click the search bar again the event is not called.
<div class=".home-search-panel">
<input type="search" data-bind="hasFocus: searchInputFocus()" name="q" placeholder="#Global.SearchPlaceholderCopy" value="#Request.QueryString["q"]" maxlength="150" class="input-product-search" autocomplete="off" />
</div>
And here's my knockoutJs code
var searchInputFocus = function () {
document.body.scrollTop = zepto('.home-search-panel').offset().top;
};
And I think this code is using DOM manipulation which is harder to test without using jquery-jasmine how to do something like this in a knockout way so i can properly test it?
My thoughts...
You should remove the () after searchInputFocus(), it should just be searchInputFocus
The hasFocus binding needs to return true or false. hasFocus doesn't check if a control has focus, it makes the control have focus if the binding parameter evaluates to true. So, if searchInputFocus returns true, then knockout will set the input box to have focus. There is a well explained example in the documentation that I really can't make any better. :-)
It sounds like what you really want is the event binding: data-bind="event: { onfocus: searchInputFocus}" In this case, the searchInputFocus function will be called when the input box has focus.
The click binding as suggested in the comments should work too. It may not have worked for you because you need to remove the () after searchInputFocus as mentioned in point 1 above. Although the click won't fire if someone tabs to the field.
Hope that helps.