I have an input box that I am trying to add functionality to. I want to write a class directive to easily add an ability to any input box. I want that when the user enters an '#', a box will pop up showing the options, using uib-typeahead. I cant figure out a way to display the box without making the original text box disappear, although ideally the box will pop up where the user is currently typing
<div class="medium-2">
<label>Age:</label>
</div>
<div class="medium-10">
<input type="text" class="form-control pop-up-variables" name="age" error-message="ageErrorMessage" required>
</input>
</div>
The block I want to be able to add is this:
<input class="variable-dropdown" type="text" uib-typeahead="number as number for number in numbers | filter:$viewValue" ng-model="selectedAttribute" placeholder="Choose variable">
</input>
I don't want to return it as a template in the directive because I dont want to replace the block that the directive is on, but I don't know how to add it correctly to the DOM.
The simple JS looks like:
app.directive('popUpVariables', function() {
return {
restrict: 'C',
controller: function($scope) {
$scope.numbers = ['One', 'Two', 'Three', 'Four', 'Five'];
},
link: function (scope, element, attrs, ngModelCtrl) {
element.on('keypress', function(event) {
if (event.which === 64) {
// This is where I want to show the second input
}
});
}
}
})
Related
I have successfully used UI Bootstrap's typeahead directive on my AngularJS pages, and I would like to create a custom directive for account selection that wraps up the typeahead with some services for fetching the account options.
The options show up just fine, but I think I'm running into issues with the ng-model passed as a $scope variable from the outer container to the custom directive - it keeps cutting me off when I try to actually type out the selection in the custom directive.
When using uib-typeahead in my outer controller it works just fine and waits forever for you to finish typing/make your selection. But when doing it in the directive, the ng-model-options: { debounce: 50 } seems to cause the user's typing to reset to empty after the debounce interval. At 50 ms I basically can get only a character or two in there, and then the $viewValue (?) is reset, and it often garbles both the possible selection and the placeholder in the text box. If I set the debounce to a higher value, then it gives me longer before it resets, but it is also that much slower to react to user input.
I'm guessing the issue has something to do with the ng-model, its underlying ngModelController and the $viewValue in there, but I'm not sure how to get it to let me finish typing.
Plunker demo can be found here
WORKS: uib-typeahead
<input type="text"
name="account2"
uib-typeahead="account as formatAccount(account) for account in accounts | filter:$viewValue"
placeholder="Select an account"
ng-model="selectedAccount"
ng-model-options="{ debounce: 50 }"
typeahead-show-hint="true"
typeahead-focus-first="true"
typeahead-editable="false"
typeahead-min-length="0"
class="form-control account-search"
autocomplete="off" />
DOESN'T WORK: Reference to the directive
<input type="text"
name="account3"
input-account
accounts="accounts"
placeholder="Select your account"
ng-model="selectedAccount" />
The impatient directive
app.directive('inputAccount', [
function() {
let directive =
{
restrict: 'A',
replace: 'true',
require: ['ngModel'],
templateUrl: 'input-account.html',
scope: {
ngModel: '=ngModel',
accounts: '=',
placeholder: '#',
name: '#',
required: '#'
},
link: linkFunction
};
return directive;
function linkFunction($scope) {
$scope.formatAccount = function (account) {
if (account) {
return `${account.id} - ${account.name}`;
}
return '';
}; // formatAccount
}
}
]); // inputAccount directive
The impatient directive's template
<input type="text"
name="{{ name }}"
placeholder="{{ placeholder }}"
ng-model="ngModel"
ng-model-options="{ debounce: 50 }"
uib-typeahead="account as formatAccount(account) for account in accounts | filter:$viewValue"
typeahead-show-hint="true"
typeahead-focus-first="true"
typeahead-editable="false"
typeahead-min-length="0"
class="form-control account-search"
autocomplete="off"
ng-required="required" />
I'm using Angular JS v1.5.5 and defined a custom input field type currency that allows entering large numbers as e.g. 1.5k or 3.4M or 4T etc. This I accomplished defining a custom directive currency. The problem is that even when the display value is shown and the model contains a valid value, and when pressing form submmit I get the You must enter a valid value error.
This is the input field configuration as shown using the IE DOM explorer:
<div class="input-group">
<input name="tradeParameters.tradeNotional" class="form-control ng-not-empty ng-valid ng-valid-required ng-dirty ng-valid-number ng-touched" id="tradeParameters_tradeNotional" required="required" type="number" step="1.0E-5" value="" ng-model="inSampleFormData.tradeParameters.tradeNotional" ng-required="true" currency="">
<span class="input-group-addon">$</span>
</div>
The MainModule.ts defines the filter and directive as follows:
.filter('identity', ['$filter', function ($filter) {
return function(input) {
return input;
};
}])
.directive("currency", function($filter, formatServices: FormatServices){
var p = function(viewValue){
if (angular.isDefined(viewValue)) {
return $filter('identity')(formatServices.currParse(viewValue));
}
};
var f = function(modelValue){
if (angular.isDefined(modelValue)) {
return $filter('identity')(formatServices.currFormat(modelValue));
}
};
return {
require: 'ngModel',
link: function(scope, ele, attr, ctrl){
ctrl.$parsers.unshift(p);
ctrl.$formatters.unshift(f);
}
};
})
I'm writing a directive to dynamically hide input field.Rules are coming from the database.If all the divs within a div are hidden then paren div's visibility is also set to none. Problem is hidden elements are not passing validation.
This is my code
return {
restrict: 'A',
priority: 0,
terminal: false,
link: function (scope, element, attrs) {
var unwatch = scope.$watchCollection('fieldRules', function (newVal, oldVal) {
if (scope.fieldRules != undefined && scope.fieldRules.length > 0) {
var elem = $(element);
var rule = $filter('filter')(scope.fieldRules, { FieldKey: attrs.key })[0];
if (element.is('div')) {
if (!rule.IsVisible) {
attrs.$set('ngHide', true);
//attrs.$set('ngIf', false);
var lastDiv = elem.siblings('div').last();
lastDiv.addClass('field-alignment');
}
else {
attrs.$set('ngShow', true);
//attrs.$set('ngIf', true);
}
var parentDiv = elem.closest('div.form-group')
if (parentDiv.find('div.input-group[ng-hide!=true]').length === 0){
parentDiv.hide();
}
}
attrs.$set('fieldRule', null);
$compile(element)(scope);
}
})
}
}
One of the solutions on stackoverflow advised to use ng-if but it also did not work.
Edit
I want angular to bypass validation for input fields which are inside a hidden div(these input fields are required means they contain attribute ng-required=true ). I have also removed the unnecessary code.
This is my html
<div field-rule data-key="minhourlyrate" class="input-group erorinner" style="width: 48%;float: left;" ng-class="{invalidField:checkFieldValidity(signupForm.minhourlyrate)}">
<span class="input-group-addon"><i class="fa fa-usd"></i></span>
<input id="txtMinHourlyRate" min="0" max="100" type="number" name="minhourlyrate" ng-model="user.MinHourlyRate" class="form-control" placeholder="Min" autofocus="" ng-pattern="/^[0-9]+(\.[0-9]{1,2})?$/" step="0.01" ng-required="true">
All I'm trying to do is hide an input field along with the div containing it through a directive.An idea to write a new directive to solve the problem is also very welcome.
I am working on a directive and I had form validation working by hard-coding the ng-show to form.birthdate.$touched && form.birthdate.$error.required. After getting this working I set out to removing the portion of that string where i'd hardcoded the name of the input to birthdate. See below in the code where I have two spans with the this field is required message. The bottom one works, the top one doesn't. If I look at it in the HTML elements panel they look identical so it seems like it should work but things are not being bound correctly. Any idea how to solve this problem?
angular.module('MyModule').directive('vrDatepicker', function() {
return {
scope: {
dateModel: '='
},
link: function(scope, element, attrs, ctrls) {
scope.id = attrs.id;
scope.name = attrs.name;
scope.required = attrs.required;
scope.form = ctrls[0];
},
controller: ['$scope', function($scope) {
// Removed b/c it doesn't matter
}],
template: '<p class="input-group">\
<input type="text" \
class="form-control"\
datepicker-popup="MMM d, yyyy"\
ng-model="dateModel"\
is-open="opened"\
show-weeks="false"\
close-text="Close" />\
<span class="input-group-btn">\
<button type="button"\
class="btn btn-default"\
ng-click="open($event)">\
<i class="glyphicon glyphicon-calendar"></i>\
</button>\
</span>\
<span ng-show="form[\'{{name}}\'].$touched && form[\'{{name}}\'].$error.required" class="text-danger">This field is required</span>\ // ### This one doesn't work
<span ng-show="form.birthdate.$touched && form.birthdate.$error.required" class="text-danger">This field is required</span>'\ // ### This one works
</p>'
}
});
This should work
<span ng-show="form[name].$touched && form[name].$error.required" class="text-danger">This field is required</span>
Everything within the string assigned to ng-show will be interpolated so you don't need all that extra syntax.
I Created js fiddle: Fiddle
I create a form with some ng-options in it, and it have strange behavior when you use the button instead of mouse (just click on the textbox and press "tab" and you can select it using arrow key).
<form ng-controller="MyApp" id="Apps" name="Apps" ng-submit="SendApp()" role="form" novalidate>
<input type="text" name="title" ng-model="Info.Title" />
<select id="Formula" ng-model ="Info.Genre" ng-change= "ChangeGenre()"
ng-options="id as name for (id, name) in Genre" blank></select>
<select class="form-control" ng-model ="Info.Program"
ng-options="Program as Name for (Program, Name) in Program" ng-change="ChangeProgram()" blank></select>
<h3>{{Info.Genre}}</h3>
<h3>{{Info.Program}}</h3>
<button type=submit>Submit this </button>
</form>
Javascript:
var theApp = angular.module("TheApp", []);
theApp.controller("MyApp", ['$scope', function($scope){
$scope.Program = {"1":"Music","2":"Theater","3":"Comedy"};
$scope.Genre = {"1":"Mystery", "2":"Thriller", "3":"Romance"};
$scope.ChangeProgram = function(){
alert($scope.Info.Program + " " + $scope.Info.Genre);
}
$scope.ChangeGenre = function (){
console.log($scope.Info.Genre);
}
$scope.SendApp = function(){
alert($scope.Info.Program + " " + $scope.Info.Genre);
}
}]);
The ng-model are not updated when you select the first options on First try.
What's Wrong, and How To Fix this?
Update:
As Mentioned on comment below, To reproduce, enter mouse into textfield, tab to combobox and try to select the second option (Thriller) using keyboard. This will fail on the first attempt, once the third or first option is selected, the second option is also recognized.
Using the the directive proposed here, this works for me:
theApp.directive("select", function() {
return {
restrict: "E",
require: "?ngModel",
scope: false,
link: function (scope, element, attrs, ngModel) {
if (!ngModel) {
return;
}
element.bind("keyup", function() {
element.triggerHandler("change");
})
}
}
})
I forked the fiddle.