javascript 如何使用 Angular JS 将一个模型绑定到多个输入

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28132939/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-28 08:28:27  来源:igfitidea点击:

How to bind one model to multiple inputs with Angular JS

javascriptangularjsangularjs-directive

提问by emersonthis

I have an form input which is for a MySQL date field. Ex: 2015-01-31.

我有一个用于 MySQL 日期字段的表单输入。例如:2015-01-31

I want to allow the user to input this using 3 different form inputs. One for the year, one for the month, and one for the day.

我想允许用户使用 3 种不同的表单输入来输入它。一为年,一为月,一为日。

Obviously ng-model isn't going to work right out of the box, because I'm trying to bind just one partof the date string to each input. I'm pretty sure the way to do it is bye creating three "temporary" scope vars/models

显然 ng-model 不会开箱即用,因为我试图将日期字符串的一部分绑定到每个输入。我很确定这样做的方法是创建三个“临时”范围变量/模型

$scope.year;
$scope.month;
$scope.day;

...and then somehow combine/binding them to the actual value.

...然后以某种方式将它们组合/绑定到实际值。

//If only it were this easy!
$scope.date = $scope.year + "-" + $scope.month + "-" + $scope.day;

The line above of course won't work because the values aren't two-way-bound. If the form were only for saving new data, I could could get away with that by just combining the inputs on submit. But I need it to handle/show existing data also. And it's going to get super ugly if I can't figure out a way to wrangle Angular's binding magic to do what I want.

上面的行当然不起作用,因为这些值不是双向绑定的。如果表单仅用于保存新数据,我可以通过在提交时组合输入来解决这个问题。但我也需要它来处理/显示现有数据。如果我无法找到一种方法来解决 Angular 的绑定魔法来做我想做的事情,那将会变得非常难看。

I found this questionwhich I think is trying to do the same thing, but they solve it with a custom directive, which is something I'm hoping to avoid. I know this may be a more maintainable/portable/modular way to do it, but I'm new to Angular and a bit intimidated by that. Also, the inputs are using the lovely angular-selectizedirective, which adds an additional layer of complexity to that approach.

我发现了这个问题,我认为它试图做同样的事情,但他们用自定义指令解决了这个问题,这是我希望避免的。我知道这可能是一种更易于维护/便携/模块化的方法,但我是 Angular 的新手,对此有点害怕。此外,输入使用了可爱的angular-selectize指令,这为该方法增加了额外的复杂性。

回答by tydotg

A directive is probably best, but these examples look overly complex. Anyway if you are hoping to avoid a directive, just use $scope.$watchand re-build your date string each time one of the important variables are updated.

指令可能是最好的,但这些示例看起来过于复杂。无论如何,如果您希望避免使用指令,只需$scope.$watch在每次更新一个重要变量时使用并重新构建您的日期字符串。

Something like this might be in your controller:

你的控制器中可能有这样的东西:

$scope.year = '';
$scope.month = '';
$scope.day = '';

// this might be able to be refactored
$scope.$watch('year', buildDate);
$scope.$watch('month', buildDate);
$scope.$watch('day', buildDate);

function buildDate() {
  $scope.date = $scope.year + "-" + $scope.month + "-" + $scope.day;
}

As a side note, this is probably what my directive logic would look like too.

作为旁注,这可能也是我的指令逻辑的样子。

Edit: Code cleanup and fiddle

编辑:代码清理和小提琴

Cleaner example - I prefer this because it groups all the date-related items with an object, which also makes watching for changes easier.

更简洁的示例 - 我更喜欢这个,因为它将所有与日期相关的项目与一个对象分组,这也使观察更改变得更容易。

$scope.date = {
    year: '',
    month: '',
    day: ''
};

// use watch collection to watch properties on the main 'date' object
$scope.$watchCollection('date', buildDate);

function buildDate(date) {
  $scope.dateString = date.year + "-" + date.month + "-" + date.day;
}

Fiddle

小提琴

回答by Peter Ashwell

here's an interesting demo that uses custom directives that are a lot less intimidating than the ones you linked to. You should be able to apply them to your inputs without too much conflict with other stuff:

这是一个有趣的演示,它使用自定义指令,这些指令比您链接的指令要少得多。您应该能够将它们应用于您的输入,而不会与其他内容发生太多冲突:

http://plnkr.co/edit/3a8xnCfJFJrBlDRTUBG7?p=preview

http://plnkr.co/edit/3a8xnCfJFJrBlDRTUBG7?p=preview

The trick is setting the parser and formatter for a model using the directive. This lets you intercept changes to the model and interact with the rest of your scope:

诀窍是使用指令为模型设置解析器和格式化程序。这使您可以拦截对模型的更改并与范围的其余部分进行交互:

app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';
  $scope.date = new Date();
});

app.directive('datePartInput', function() {
  return {
    restrict: 'A',
    require: 'ngModel',
    link: function(scope, elem, attrs, ngModel) {
      var part = attrs.part;
      var modelToUser, userToModel
      console.log('part:', part);
      if (part == 'year') {
        modelToUser = function(date) {
          return date.getFullYear();
        }
        userToModel = function(year) {
          ngModel.$modelValue.setYear(year);
          return ngModel.$modelValue
        }
      }
      else if (part == 'month') {
        modelToUser = function(date) {
          return date.getMonth();
        }
        userToModel = function(month) {
          ngModel.$modelValue.setMonth(month);
          return ngModel.$modelValue;
        }
      }
      else if (part == 'day') {
        modelToUser = function(date) {
          return date.getUTCDate();
        };
        userToModel = function(day) {
          ngModel.$modelValue.setUTCDate(day);
          return ngModel.$modelValue;
        };
      }
      ngModel.$formatters.push(modelToUser);
      ngModel.$parsers.push(userToModel);
    }
  }
})

And the template:

和模板:

<body ng-controller="MainCtrl">
  <p>Hello {{name}}!</p>
  {{date |  date}}
  <input date-part-input part="year" ng-model="date">
  <input date-part-input part="month" ng-model="date">
  <input date-part-input part="day" ng-model="date">
</body>

回答by Wayne Ellery

You can create a re-usable directive that has the three fields in it so it can be used for all date fields. The model for the directive is aliased to dateon the isolated scope. To get each of the date parts the date is then split and then year, monthand dayare assigned to scope properties. Then when one of the fields is changed the date property is updated by appending them together with the -separator.

您可以创建一个包含三个字段的可重用指令,以便它可用于所有日期字段。该指令的模型别名为date隔离作用域。要获得每个日期部分然后将日期被分割,然后的yearmonth并且day被分配给范围的性质。然后,当其中一个字段发生更改时,通过将它们与-分隔符一起附加来更新日期属性。

For this directive I've just hard coded, years months and days. I'd recommend to use some javascript date functions to populate them so they aren't hard coded.

对于这个指令,我只是硬编码,年月日。我建议使用一些 javascript 日期函数来填充它们,这样它们就不会被硬编码。

angular
.module('app')
.directive('dateSelect', function (){
    return {
        restrict: 'E',
        replace: true,
        scope: {
          date:'=ngModel'
        },
        template: '<div class="dateSelect"><div class="dateField"><selectize placeholder="Select a year..." config="yearConfig" ng-model="year" ng-change="dateChanged()"></selectize></div>' +
        '<div class="dateField"><selectize placeholder="Select a month..." config="monthConfig" ng-model="month" ng-change="dateChanged()"></selectize></div>' + 
        '<div class="dateField"><selectize placeholder="Select a day..." config="dayConfig" ng-model="day" ng-change="dateChanged()"></selectize></div></div>',
        controller: function ($scope) {
          $scope.yearConfig = {
          options: [{value: 2013, text: '2013'}, {value: 2014, text:'2014'}, {value: 2015, text:'2015'}],
          create: true,
          sortField: 'value',
          maxItems: 1,
        };
        $scope.monthConfig = {
          options: [{value: '01', text: '1'}, {value: '02', text: '2'}, {value: '03', text:'3'}, 
          {value: '04', text: '4'}, {value: '05', text:'5'}, {value: '06', text:'6'}, {value: '07', text: '7'}, {value: '08', text:'8'}, {value: '09', text:'9'},
          {value: '10', text: '10'}, {value: '11', text:'11'}, {value: '12', text:'12'}],
          create: true,
          sortField: 'value',
          maxItems: 1,
        };

        $scope.dayConfig = {
          options: [{value: '01', text: '1'}, {value: '02', text: '2'}, {value: '03', text:'3'}, 
          {value: '04', text: '4'}, {value: '05', text:'5'}, {value: '06', text:'6'}, {value: '07', text: '7'}, {value: '08', text:'8'}, {value: '09', text:'9'},
          {value: '10', text: '10'}, {value: '11', text:'11'}, {value: '12', text:'12'}],
          create: true,
          sortField: 'value',
          maxItems: 1,
        };

        $scope.dateChanged = function () {
          if (!angular.isUndefined($scope.year) && !angular.isUndefined($scope.month) && !angular.isUndefined($scope.day)) {
            $scope.date = $scope.year + "-" + $scope.month + "-" + $scope.day;
          }
        }

        if (!angular.isUndefined($scope.date)) {
          var dateParts = $scope.date.split("-");

          if (dateParts.length === 3) {
            $scope.year = dateParts[0];
            $scope.month = dateParts[1];
            $scope.day = dateParts[2];
          }
        }
      }
    };
});

Plunkr

普朗克