2015-03-16 5 views
0

Я использую нг-повтора, чтобы создать ряд полей ввода в форме:Необходимо обновить модель внутри AngularJS директивы с помощью сенсорного экрана

<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> 

я использую некоторые CSS, чтобы скрыть стандартный ввод: тип = число прядильщики, используя следующую директиву для создания кнопок, более подходящих для использования на сенсорном экране.

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); 
      } 
     } 
    }; 
}]); 

Шаблон выглядит следующим образом:

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

Это хорошо работает для одного вопроса, за исключением. Нам нужно только одно из полей ввода, чтобы иметь значение. Когда форма отправляется, запускается другая директива (см. Приведенную выше проверку числа). Это просто проверяет, имеет ли какое-либо из значений модели что-то большее, чем нуль. Если это так, то проверяется контроль. Однако, если пользователь использует сенсорный экран и увеличивает значение для одного из полей дальше по странице, каждое поле ввода до поля со значением считается недействительным. Это связано с тем, что до тех пор, пока он фактически не попадет в поле со значением, значение модели не будет установлено. Я сбрасывал массив модели (form.numberArray) в консоль в директиве проверки и мог видеть, что каждое значение добавлялось при каждом запуске директивы проверки.

Что мне нужно - это обновить модель при нажатии кнопки. Я попытался использовать scope. $ Parent. $ Apply, но просто получил ошибку «in progress».

Любые предложения, рекомендации или рекомендации с благодарностью получены.

ответ

0

Вот решение, с которым я столкнулся. Обратите внимание, что в коде я использую «префикс» в качестве заполнителя для любого префикса, который вы можете использовать, чтобы отличить вашу логику от AngularJS. У меня есть несколько директив для обработки сенсорного начала и конца:

directives.directive('prefixTouchstart', function() { 
    return { 
     restrict: 'A', 
     link: function (scope, element, attrs) { 
      element.on('touchstart', function (event) { 
       scope.$apply(function() { 
        scope.$eval(attrs.prefixTouchstart); 
       }); 
      }); 
     } 
    } 
}); 

directives.directive('prefixTouchend', function() { 
    return { 
     restrict: 'A', 
     link: function (scope, element, attrs) { 
      element.on('touchend', function (event) { 
       scope.$apply(function() { 
        scope.$eval(attrs.prefixTouchend); 
       }); 
      }); 
     } 
    } 
}) 

я затем использовать следующую директиву для создания полого ввода. Обратите внимание, что прикосновение к одной из кнопок и удерживание пальца будет постепенно увеличивать/уменьшать поле ввода. Модель обновляется только тогда, когда срабатывает событие touch end. Причина этого в обновлении модели в логике setInterval работает, AngularJS не отражает эти изменения в пользовательском интерфейсе, и мы не можем вызывать $ apply, потому что мы просто получим ошибки «in progress» ($ apply вызывается в директивах touchstart/touchend, см. выше).

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

    return { 
     restrict: 'E', 
     templateUrl: 'html-templates/numeric-input.html', 
     transclude: true, 
     scope: { 
      prefixName: '@', 
      prefixModel: '=', 
      prefixPlaceholder: '@' 
     }, 

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

      var intervalId, inputElement = element.find('input'); 
      var currentValue = scope.prefixModel ? scope.prefixModel : 0; 
      inputElement.addClass('form-control'); 

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

      function decrementCurrentValue() { 
       if (currentValue > 0) { 
        --currentValue; 
        return true; 
       } 
       return false; 
      } 

      function decrement() { 
       if (decrementCurrentValue()) { 
        inputElement[0].value = currentValue; 
       } 
      } 

      scope.increment = function() { 
       scope.prefixModel = ++currentValue; 
      }; 

      scope.decrement = function() { 
       if (decrementCurrentValue()) { 
        scope.prefixModel = currentValue; 
       } 
      }; 

      scope.incrementStart = function() { 
       inputElement[0].value = ++currentValue; 
       intervalId = setInterval(function() { 
        inputElement[0].value = ++currentValue; 
       }, 100); 
      } 

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

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

Ниже приведен шаблон HTML:

<div class="input-group column calc-width"> 
    <span class="input-group-addon">{{prefixName}}</span> 
    <input type="number" min="0" id="{{prefixName}}" data-ng-model="prefixModel" placeholder="{{prefixPlaceholder}}" /> 
</div> 

код, который создает поля выглядит следующим образом:

<div class="col-sm-6 input" data-ng-repeat="value in values"> 
    <prefix-numeric-input data-prefix-name="{{ value.name }}" data-prefix-model="form.valueArray[value.name]" data-prefix-placeholder="Enter some sort of value here"></prefix-numeric-input> 
</div> 

Мы используем Bootstrap, следовательно, классы CSS завален по всей логике. Надеюсь, это поможет кому-то.

Смежные вопросы