Angular JS dual input Directive UpDate View Value - javascript

Hi I have a situation here,
I have created a dual input directive. Can you please help to in the below scenario.
When I change the model value via controller to undefined, the view values are not cleared. Here is the Codes,
My Dual Input Directive is as follows,
angular.module("awcQuoteBuy.directives")
.directive('dualInput', function($timeout, inputValidationService) {
return {
restrict: 'E',
templateUrl: 'app/partials/common/doubleInput.html',
scope: {
modelValue: '=',
size: '#',
fieldError: '#',
blurFn: '&loseFocus'
},
link: function postLink(scope, element, attrs, ctrl) {
scope.leftFocused = false;
scope.rightFocused = false;
scope.$watch('left', function(newVal, oldVal) {
if (newVal!==oldVal) {
var tmp = (newVal) ? inputValidationService.formatNumber(newVal+'') : '';
scope.modelValue = tmp + '|'+ scope.getOtherValue(scope.right);
}
});
scope.$watch('right', function(newVal, oldVal) {
if (newVal!==oldVal) {
var tmp = (newVal) ? inputValidationService.formatNumber(newVal+'') : '';
scope.modelValue = scope.getOtherValue(scope.left) + '|' + tmp;
}
});
scope.getOtherValue = function(value) {
return (value && value!=='') ? inputValidationService.formatNumber(value+'') : '';
};
//will set the value initially
$timeout(function() {
if (!scope.modelValue || scope.modelValue===null) {
scope.modelValue = '';
}
if (scope.modelValue!=='') {
var splitIndex = scope.modelValue.indexOf('|');
if (splitIndex>=0) {
var values = scope.modelValue.split('|');
scope.left = values[0];
scope.right = values[1];
} else {
scope.left = scope.modelValue;
}
}
});
/*
Below functions will add on-blur (lose focus) support to both fields.
*/
scope.focusLeft = function() {
scope.leftFocused = true;
};
scope.blurLeft = function() {
scope.leftFocused = false;
$timeout(function() {
if (!scope.rightFocused) {
scope.blurFn();
}
}, 100);
};
scope.focusRight = function() {
scope.rightFocused = true;
};
scope.blurRight = function() {
scope.rightFocused = false;
$timeout(function() {
if (!scope.leftFocused) {
scope.blurFn();
}
}, 100);
};
}
};
});
The HTML Piece of code is as follows,
<dual-input model-value="dualInput[$index]" ng-switch-when="DUAL_NUMBER" size="{{q.length}}"
field-error="{{q.invalid || (nextClicked && !validateGeneralQuestion(acc.memberId, q))}}" id="{{'gQDual'+$index}}"
lose-focus="saveGeneralAnswer(acc.memberId, q)"></dual-input>
In My Controller when I set the scope value to undefined or null, the entered values in the view is not cleared. Please help me here what I should do to clear this value
$scope.dualInput[$index]=undefined;

The directive itself has got the auto initialize feature. So I had to re render the directive whenever I wanted to reinitialize.
If you want to explicitly update user ctrl.$setViewvalue = ""

Related

angular directive - element.(...) is undefined

I am working on a directive and I am facing an issue.
Basically, in my directive I am trying to use a plugin (this: https://github.com/soundar24/roundSlider) and I am getting this error:
element.roundSlider is not a function
The code for my directive is the following:
angular.module('myPicker', []).directive('picker', [
"$timeout", function($timeout) {
var linkFunction, setColor;
setColor = function(value) {
var el, temperatureValue;
el = $('.rs-range-color');
temperatureValue = parseInt(value);
el.attr('class', '');
return el.addClass('rs-path rs-transition rs-range-color animate-color-change temp-' + temperatureValue);
};
$.fn.roundSlider.prototype.defaults.create = function() {
var endLabel, numberTag1, numberTag2, o, startLabel;
o = this.options;
startLabel = this._valueToAngle(o.min);
numberTag1 = this._addSeperator(startLabel, 'rs-tooltip-text custom-label num1 ');
numberTag1.children().html(o.min).rsRotate(-startLabel);
endLabel = this._valueToAngle(o.max);
numberTag2 = this._addSeperator(endLabel, 'rs-tooltip-text custom-label num2 ');
numberTag2.children().html(o.max).rsRotate(-endLabel);
return setColor(o.value);
};
linkFunction = function(scope, element, attrs) {
var hiddenElement;
element.roundSlider({
min: attrs.min,
max: attrs.max,
radius: attrs.size,
sliderType: 'min-range',
startAngle: 315,
circleShape: 'pie',
width: attrs.width,
value: attrs.value,
step: 0.5,
editableTooltip: false,
tooltipFormat: function(attrs) {
return attrs.value.toFixed(1) + ' °C';
}
});
if (scope.tempPicker.provvisorial === null) {
scope.tempPicker.provvisorial = attrs.value;
}
element.on('change drag', function(e) {
if (e.value !== void 0) {
return scope.$apply(function() {
return setColor(e.value);
});
}
});
element.on('stop', function(e) {
return scope.tempPicker.provvisorial = e.value;
});
element.on('change', function(e) {
return scope.tempPicker.provvisorial = e.value;
});
scope.$on('$destroy', function() {
element.roundSlider("destroy");
return element.remove();
});
hiddenElement = angular.element("#picker-hidden-text-box");
return hiddenElement.on('change', function() {
element.roundSlider("option", "value", parseInt(hiddenElement.val()));
return scope.tempPicker.provvisorial = parseInt(hiddenElement.val());
});
};
return {
restrict: 'E',
templateUrl: './directives/Picker/Picker.tpl.html',
replace: true,
link: linkFunction
};
}
]);
Now, what I don't understand is:
I am also modifying a function for roundSlider plugin $.fn.roundSlider.prototype.defaults.create = function() {... and it works here. I can see that $.fn.roundSlider is actually there and not undefined.
I really don't know why it's doing this, any idea?
I also tried to use angular.element.roundSlider(like pointed here: https://medium.com/#darilldrems/angularjs-jquery-in-angularjs-directive-96ad3d150d86#.4mc3ymoq6) but I get the same error
If you need any other piece of code, don't hesitate to ask
thanks
Try adding roundSlider javascript before making use of it
At the end, I fixed it adding
element = $(el)
element.roundSlider
it's working now

How to use directives for multiple form elements

I want to check if an input is katakana characters or not.
This code works for one element :
var KANA_FULL_SIZE_REGEXP = /^([ァ-ン。、ー「」.\s]+)$/;
var KANA_HAFL_SIZE_REGEXP = /^([ァ-ン゙゚。「」、・ー\s]+)$/;
var KANA_ALL_SIZE_REGEXP = /^([ァ-ンァ-ン゙゚。`-「」.。、ー「」・\s]+)$/;
app.directive('kataKana', function() {
return {
// restrict: 'A',
// scope: {},
require: '?ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
if(!ngModelCtrl) {
return;
}
if (ngModelCtrl.$isEmpty(element.val())) {
scope.kanaerror = false;
}
element.bind('keypress', function(event) {
if(event.keyCode === 32) {
event.preventDefault();
}
});
/**
* var setObjFill
* setObjFill == 0 check katakana full size and half size
* setObjFill == 1 check katakana only full size
* setObjFill == 2 check katakana only half size
*/
element.bind('keyup', function(event) {
if (!element.val() || element.val() == null || element.val() == '') {
scope.kanaerror = false;
} else {
var setObjFill = attrs.kataKana.split(',');
if(setObjFill == 0) {
if (KANA_ALL_SIZE_REGEXP.test(element.val())) {
scope.kanaerror = false;
} else {
scope.kanaerror = true;
}
} else if (setObjFill == 1) {
console.log('ee');
if (KANA_FULL_SIZE_REGEXP.test(element.val())) {
scope.kanaerror = false;
} else {
scope.kanaerror = true;
}
} else {
if (KANA_HAFL_SIZE_REGEXP.test(element.val())) {
scope.kanaerror = false;
} else {
scope.kanaerror = true;
}
}
}
scope.$apply();
});
}
};
});
in html:
<input id="txt_kana" kata-kana="1" name="txt_kana">
The problem
If in that form we use kata-kana="1" twice, my code always return true or false for two elements using kata-kana="1". Because my code return scope.kanaerror. But I don't know how to resolve that problem.
I guess you want to check if the input is Katakana japanese language by watching scope.kanaerror which is a share scope. if you have multiple inputs but your scope.kanaerror is only one, then scope is not issolated that why you always get true or false(i guess).
I suggest you use ng-model for your input and check the model itself for each input if you have them more than two.
<input id="txt_kana" ng-model='input1' kata-kana name="txt_kana">
<input id="txt_kana" ng-model='input2' kata-kana name="txt_kana">
And in your directive:
app.directive('kataKana', function() {
return {
// restrict: 'A',
// scope: {},
require: '?ngModel',
link: function(scope, element, attrs, ngModelCtrl) {
var KANA_ALL_SIZE_REGEXP = /\d+/g;
var KANA_FULL_SIZE_REGEXP = /[A-Z]/g;
var KANA_HAFL_SIZE_REGEXP = /[a-z]/g;
ngModelCtrl.$parsers.push(function(viewValue) {
// this is to limit input charactor
element.bind('keypress', function(event) {
if (event.keyCode === 5) {
event.preventDefault();
return false;
}
});
if (!viewValue) {
return false; // return to modelValue for controller
}
if (KANA_ALL_SIZE_REGEXP.test(viewValue)) {
return 'helo'; // return to modelValue for controller and interpolation
} else if (KANA_FULL_SIZE_REGEXP.test(viewValue)) {
return 'hi'; //return to modelValue for controller
} else if (KANA_HAFL_SIZE_REGEXP.test(viewValue)) {
return 'hey'; //return to modelValue for controller
}
})
}
};
});
I refactor your code but as I cannot type japanese so I change Regex. I hope you get the idea. in my code I make use the ngModelcontroler.$parsers and viewValue to return modelValue which use by controller and interpolation. Here is a working plunker. hope that help.
Change the line
// scope: {},
to
scope: true,
This will give each instance it's own scope that is inherited from the parent scope. At the moment they are all sharing the parent scope and when one attaches kanaerror to the scope it is on all.
My solution is return true or false not scope. And it's working.
link: function(scope, element, attrs, ngModelCtrl) {
if(!ngModelCtrl) {
return;
}
/**
* var setObjFill
* setObjFill == 0 check katakana full size and half size
* setObjFill == 1 check katakana only full size
* setObjFill == 2 check katakana only half size
*/
ngModelCtrl.$validators.katakana = function(model, value) {
if (value == '' || value == undefined){
return true;
}
var setObjFill = attrs.kataKana.split(',');
if (setObjFill == 0) {
var test = KANA_ALL_SIZE_REGEXP.test(value);
} else if (setObjFill == 1) {
var test = KANA_FULL_SIZE_REGEXP.test(value);
} else {
var test = KANA_HAFL_SIZE_REGEXP.test(value);
}
return test;
};
}

Could anybody explain what these lines mean or how do they work please (marked as bold)?

angular.isUndefined(attr.isEnabled) && attr.$set('isEnabled', 'true');
sideMenuCtrl[$scope.side]
IonicModule
.directive('ionSideMenu', function() {
return {
restrict: 'E',
require: '^ionSideMenus',
scope: true,
compile: function(element, attr) {
angular.isUndefined(attr.isEnabled) && attr.$set('isEnabled', 'true');
angular.isUndefined(attr.width) && attr.$set('width', '275');
element.addClass('menu menu-' + attr.side);
return function($scope, $element, $attr, sideMenuCtrl) {
$scope.side = $attr.side || 'left';
var sideMenu = sideMenuCtrl[$scope.side] = new ionic.views.SideMenu({
width: attr.width,
el: $element[0],
isEnabled: true
});
$scope.$watch($attr.width, function(val) {
var numberVal = +val;
if (numberVal && numberVal == val) {
sideMenu.setWidth(+val);
}
});
$scope.$watch($attr.isEnabled, function(val) {
sideMenu.setIsEnabled(!!val);
});
};
}
};
});
angular.isUndefined(attr.isEnabled) && attr.$set('isEnabled', 'true');
This means:
if attribute isEnabled is undefined, set the isEnabled attribute to true.
It's a pretty standard way of chaining expressions using logical operators.
var sideMenu = sideMenuCtrl[$scope.side] = new ionic.views.SideMenu({...
This one assigns the value of new ionic.views.SideMenu({... to sideMenuCtrl[$scope.side] and a new variable named sideMenu.
Also pretty standard, double assignment, just like:
var x, y;
x = y = 5; // now both x and y are 5

Angular js directive doesn't work on page load

I am new to angularjs the below directive is to support decimal and commas, it works fine when a change is made to the field how ever the data in the fields are not validated when the page loads
var app = angular.module('myApply.directives', [], function () {
});
app.directive('numericDecimalInput', function($filter, $browser, $locale,$rootScope) {
return {
require: 'ngModel',
priority: 1,
link: function($scope, $element, $attrs, ngModelCtrl) {
var replaceRegex = new RegExp($locale.NUMBER_FORMATS.GROUP_SEP, 'g');
var fraction = $attrs.fraction || 0;
var listener = function() {
var value = $element.val().replace(replaceRegex, '');
$element.val($filter('number')(value, fraction));
};
var validator=function(viewValue) {
ngModelCtrl.$setValidity('outOfMax', true);
ngModelCtrl.$setValidity(ngModelCtrl.$name+'Numeric', true);
ngModelCtrl.$setValidity('rangeValid', true);
if(!_.isUndefined(viewValue))
{
var newVal = viewValue.replace(replaceRegex, '');
var newValAsNumber = newVal * 1;
// check if new value is numeric, and set control validity
if (isNaN(newValAsNumber)) {
ngModelCtrl.$setValidity(ngModelCtrl.$name + 'Numeric', false);
} else
{
if (newVal < 0) {
ngModelCtrl.$setValidity(ngModelCtrl.$name + 'Numeric', false);
}
else {
newVal = newValAsNumber.toFixed(fraction);
ngModelCtrl.$setValidity(ngModelCtrl.$name + 'Numeric', true);
if (!(_.isNull($attrs.maxamt) || _.isUndefined($attrs.maxamt))) {
var maxAmtValue = Number($attrs.maxamt) || Number($scope.$eval($attrs.maxamt));
if (newVal > maxAmtValue) {
ngModelCtrl.$setValidity('outOfMax', false);
} else {
ngModelCtrl.$setValidity('outOfMax', true);
}
if(!(_.isNull($attrs.minamt) || _.isUndefined($attrs.minamt)))
{
var minAmtValue = Number($attrs.minamt)|| Number($scope.$eval($attrs.minamt));
if((newVal > maxAmtValue) || (newVal < minAmtValue)){
ngModelCtrl.$setValidity('rangeValid', false);
}
else
{
ngModelCtrl.$setValidity('rangeValid', true);
}
}
}
else if((!(_.isNull($attrs.minamt) || _.isUndefined($attrs.minamt))))
{
var minAmtValue = Number($attrs.minamt)|| Number($scope.$eval($attrs.minamt));
if(newVal < minAmtValue)
{
ngModelCtrl.$setValidity('outOfMin', false);
}
else
{
ngModelCtrl.$setValidity('outOfMin', true);
}
}
else {
ngModelCtrl.$setValidity('outOfMax', true);
}
}
}
return newVal;
}
};
// This runs when the model gets updated on the scope directly and keeps our view in sync
ngModelCtrl.$render = function() {
ngModelCtrl.$setValidity('outOfMax', true);
ngModelCtrl.$setValidity(ngModelCtrl.$name+'Numeric', true);
$element.val($filter('number')(ngModelCtrl.$viewValue, fraction));
};
$element.bind('change', listener);
$element.bind('keydown', function(event) {
var key = event.keyCode;
// If the keys include the CTRL, SHIFT, ALT, or META keys, home, end, or the arrow keys, do nothing.
// This lets us support copy and paste too
if (key == 91 || (15 < key && key < 19) || (35 <= key && key <= 40))
return;
});
$element.bind('paste cut', function() {
$browser.defer(listener);
});
ngModelCtrl.$parsers.push(validator);
ngModelCtrl.$formatters.push(validator);
}
};
});
Could some one please let me know as what I am missing .
Thanking you in advance.
Have you declared your app (doesn't show this in your code)? ie:
var app = angular.module('app', []);
Do you have ng-app in your HTML document anywhere?
<html lang="en-GB" ng-app="app">
Check out the documentation to get started with modules (Angular is very well documented, well worth reading): https://docs.angularjs.org/guide/module
app.directive('numericDecimalInput', function($filter, $browser, $locale,$rootScope) {
return {
require: 'ngModel',
priority: 1,
link: function($scope, $element, $attrs, ngModelCtrl) {
...
validator($element.val());
}
};
});

set dynamic options on angular chosen

I am using Angular-chosen and I am unable to set dynamic options.
<div ng-init="delegate.getCategories()">
<select chosen="" multiple="multiple"
ng-model="tags" ng-change="delegate.getCategories()"
ng-options="s.categoryName for s.categoryName in tagsList">
</select>
</div>
My controller class
getCategories: function(){
constantsService.getCategories($scope.category, this.onGetCategories, this.onFailure);
alert($scope.category);
},
onGetCategories:function(response){
$scope.tagsList = response.categories;
alert(response);
},
onFailure:function(response){
alert(response);
}
on page load the init gets the categories form the backend and and sets in tagsList variable but its not there when the html loads.
my directive angular-chosen is working nice, see the codes:
HTML:
<select id="selectWithChosen"
name="selectWithChosen"
data-ng-model="theSelectedChosenValue"
data-ng-options="tp as tp.alias for tp in myList"
sgc-chosen
data-width="('100%')">
<option value="">Select One Element</option>
</select>
JavaScript which load the content of myList
$http.get("/settings/myList").success(function(data) {
$scope.myList = data;
});
I can acess the value that user selected with the next code:
//the value of my select with chosen is here, in JS:
//**remember** the variable "theSelectedChosenValue" is only fill after you select the value on chosen component.
$scope.theSelectedChosenValue;
Finally, the implementation of my angular-chosen directive:
"use strict";
// baseado em https://github.com/localytics/angular-chosen
components.directive('sgcChosen', function($timeout) {
var __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
var CHOSEN_OPTION_WHITELIST, NG_OPTIONS_REGEXP, isEmpty, snakeCase;
NG_OPTIONS_REGEXP = /^\s*(.*?)(?:\s+as\s+(.*?))?(?:\s+group\s+by\s+(.*))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+(.*?)(?:\s+track\s+by\s+(.*?))?$/;
CHOSEN_OPTION_WHITELIST = ['noResultsText', 'allowSingleDeselect', 'disableSearchThreshold', 'disableSearch', 'enableSplitWordSearch', 'inheritSelectClasses', 'maxSelectedOptions',
'placeholderTextMultiple', 'placeholderTextSingle', 'searchContains', 'singleBackstrokeDelete', 'displayDisabledOptions', 'displaySelectedOptions', 'width'];
snakeCase = function(input) {
return input.replace(/[A-Z]/g, function($1) {
return "_" + ($1.toLowerCase());
});
};
isEmpty = function(value) {
var key;
if (angular.isArray(value)) {
return value.length === 0;
} else if (angular.isObject(value)) {
for (key in value) {
if (value.hasOwnProperty(key)) {
return false;
}
}
}
return true;
};
return {
restrict: 'A',
require: '?ngModel',
terminal: true,
link: function(scope, element, attr, ngModel) {
var chosen, defaultText, disableWithMessage, empty, initOrUpdate, match, options, origRender, removeEmptyMessage, startLoading, stopLoading, valuesExpr, viewWatch;
attr.noResultsText = attr.noResultsText ? attr.noResultsText : "'Sem resultados para: '";
element.children('chosen-search').children().attr('maxlength', 100);
element.addClass('localytics-chosen');
options = scope.$eval(attr.chosen) || {};
angular.forEach(attr, function(value, key) {
if (__indexOf.call(CHOSEN_OPTION_WHITELIST, key) >= 0) {
return options[snakeCase(key)] = scope.$eval(value);
}
});
startLoading = function() {
return element.addClass('loading').trigger('chosen:updated');
};
stopLoading = function() {
scope.$evalAsync(function() {
return element.removeClass('loading').trigger('chosen:updated');
});
};
chosen = null;
defaultText = null;
empty = false;
initOrUpdate = function() {
if (chosen) {
scope.$evalAsync(function() {
return element.trigger('chosen:updated');
});
} else {
chosen = element.chosen(options).data('chosen');
chosen.search_field[0].setAttribute('maxlength', 100);
return defaultText = chosen.default_text;
}
};
removeEmptyMessage = function() {
empty = false;
return element.attr('data-placeholder', defaultText);
};
disableWithMessage = function() {
empty = true;
scope.$evalAsync(function() {
return element.attr('data-placeholder', '').attr('disabled', true).trigger('chosen:updated');
});
};
if (ngModel) {
origRender = ngModel.$render;
ngModel.$render = function() {
origRender();
return initOrUpdate();
};
viewWatch = function() {
return ngModel.$viewValue;
};
scope.$watch(viewWatch, ngModel.$render, true);
} else {
initOrUpdate();
}
attr.$observe('disabled', function(isDisabled) {
scope.$evalAsync(function() {
element.prop('disabled', isDisabled);
element.trigger('chosen:updated');
});
return true;
});
if (attr.ngOptions && ngModel) {
match = attr.ngOptions.match(NG_OPTIONS_REGEXP);
valuesExpr = match[7];
return scope.$watchCollection(valuesExpr, function(newVal, oldVal) {
if (angular.isUndefined(newVal)) {
return startLoading();
} else {
if (empty) {
removeEmptyMessage();
}
stopLoading();
if (isEmpty(newVal)) {
return disableWithMessage();
} else {
element.attr('data-placeholder', '').attr('disabled', false).trigger('chosen:updated');
}
}
});
}
}
};
});
This angular-chosen code is available HERE.

Categories

Resources