dimanche 15 mars 2015

Need to update model from within AngularJS directive using touch screen

I use ng-repeat to create a series of input fields on a form:



<div class="col-sm-6 input" data-ng-repeat="v in values">
<div data-prefix-numeric-input data-prefix-name="{{ v.name }}">
<input type="number" id="{{v.name}}" data-ng-model="form.numberArray[v.name]" data-number-validation />
</div>
</div>


I use some css to hide the standard input:type=number spinners, using the following directive to create buttons more suitable for use on a touch screen device.



directives.directive('prefixNumericInput', ['$compile', function ($compile) {

function getInputElement(attrs, element) {
var inputTagType = attrs['cpNumericInput'].length ? attrs['cpNumericInput'] : 'input';
return element.find(inputTagType);
}

function getInputValue(element) {
var currentValue = element[0].valueAsNumber;
return isNaN(currentValue) ? 0 : currentValue;
}

return {
restrict: 'A',
templateUrl: 'html-templates/numeric-input.html',
replace: false,
transclude: true,
require: '^form',
scope: {
prefixName: '@'
},

link: function (scope, element, attrs, formController, transcludeFn) {

transcludeFn(function (clone) {
var placeholder = element.find('placeholder');
placeholder.replaceWith(clone);
});

var intervalId, inputElement = getInputElement(attrs, element);
inputElement.addClass('form-control');

// Add our buttons after the input's parent element
$(inputElement[0].parentElement).after($compile('<div class="float-right">' +
'<button type="button" class="btn btn-primary inc-button" data-cp-touchstart="incrementStart()" data-cp-touchend="stop()" data-ng-click="increment()">+</button>' +
'<button type="button" class="btn btn-primary inc-button" data-cp-touchstart="decrementStart()" data-cp-touchend="stop()" data-ng-click="decrement()">-</button>')(scope));

function increment() {
inputElement[0].value = 1 + getInputValue(inputElement);
scope.$parent.$digest();
}

function decrement () {
var currentValue = getInputValue(inputElement);
inputElement[0].value = currentValue > 0 ? currentValue - 1 : 0;
}

scope.increment = increment;

scope.decrement = decrement;

scope.incrementStart = function () {
increment();
intervalId = setInterval(increment, 100);
}

scope.stop = function () {
clearInterval(intervalId);
}

scope.decrementStart = function () {
decrement();
intervalId = setInterval(decrement, 100);
}
}
};
}]);


The template is as follows:



<div class="input-group">
<span class="input-group-addon">{{prefixName}}</span>
<placeholder></placeholder>
</div>


This works well except for one issue. We only need one of the input fields to have a value. When the form is submitted another directive is run (cf. the number-validation above). This simply checks if any of the model values have something greater than zero entered. If so it validates the control in question. However if the user uses a touch screen and increments the value for one of the fields further down the page, every input field up to the field with the value is seen as invalid. This is because until it actually gets to the field with the value the model value doesn't appear to be set. I dumped the model array (form.numberArray) to the console in the validation directive and could see that each value was being appended each time the validation directive was run.


What I need is to have the model update when the button is touched. I tried using scope.$parent.$apply but simply got an 'in progress' error.


Any suggestions, guidance or recommendations gratefully received.


Aucun commentaire:

Enregistrer un commentaire