角度指令创建 - 使用多个模板

时间:2014-08-09 16:09:03

标签: javascript angularjs angularjs-directive angular-ui

我是Angular JS的新手,我正在尝试创建一个datepicker指令。它不会像Angular UI Bootstrap datepicker那样工作,因为它不会使用文本框,而是使用整页日历,您可以轻扫并点击一天(这将更新ngModel)。

我的计划是拥有一个具有renderMonth()函数的指令。此函数将接受一个月作为参数,并生成数组中的所有行/天,然后绑定到该月的模板。

我的问题是我可以在我的指令声明中为datepicker指定一个模板,但我不知道如何为行/天等指定模板并加载它们并绑定它们。我可以使用jQuery和大量的字符串集合来做到这一点,但这似乎都是错误的。

我一直在阅读Angular UI Datepicker的源代码,但作为一个新手,它对我来说没什么意义。他们已将所有内容分解为许多子指令(月指令,年份指令等),并且他们有自己的模板,但这不是我想要做的,因为我的Angular技能不会延伸到创建与每个通信的指令其他。 Angular UI代码对我来说太复杂了。

我喜欢的一件事是他们在模板中使用现有的指令,例如ng-repeat,并将它们绑定到数组或行/天。对我来说,我需要在每次调用renderMonth()时加载模板并编译模板,因为它中有现有的指令。

所以,基本上我的问题是,是否有人有任何关于如何将模板导入我的渲染函数,编译它并将其绑定到我的指令范围内的行/日数据的示例。

我会说实话。我不知道我是否说出任何意义。我只是输入听起来含糊不清的单词。

我需要的是有人指出我正确的方向。感谢。

1 个答案:

答案 0 :(得分:4)

正如评论中所讨论的,我个人不会过分担心导入模板,$compile函数或任何复杂的相对简单的标记。

我已经创建了一个(非常)基本准系统 plunker here ,以展示我的方法。我使用moment.js来处理日期,因为我对vanilla javascript日期操作非常糟糕,并且发现它非常笨拙。

这是模板:

<div class="controls">
  <button ng-click="prevMonth()"><-</button>
  <span>{{selected.format('MMMM')}}</span>
  <button ng-click="nextMonth()">-></button>
</div>
<div class="month">
  <span class="day" ng-repeat="day in selected.days">
    {{day.number}}
  </span>
</div>

模板依赖于具有selected属性的范围,该属性是一个时刻对象。它所做的只是创建一些按钮来更改月份并在顶部显示月份名称,然后为该月的每一天创建一个跨度。

一小部分CSS将日期分为7行:

span.day{
  float: left;
  width: 25px;
}
span.day:nth-child(7n+1){
  clear:left;
}

这是指令的link功能:

link: function(scope, element, attributes){
  // Set the selection to now initially.
  scope.selected = moment();

  generateDaysArray = function(){
    // -- REMOVED FOR BREVITY -- //
    return days;
  }
  // Watch the month for changes and update the days array
  scope.$watch(
    function(){
      return scope.selected.month();
    },
    function(newVal, oldVal){
      scope.selected.days = generateDaysArray();
    }
  )
  // Control button actions
  scope.nextMonth = function(){
    scope.selected.add('month', 1)
  }
  scope.prevMonth = function(){
    scope.selected.subtract('month', 1)
  }
}

确实没有什么特别之处,但请注意所使用的$watch命令利用了你可以传递一个函数而不是一个字符串的事实(尽管现在你可以使用{{1作为一个字符串)。

如果你想将日期与一周中的几天对齐,那么生成days数组会稍微复杂一些,这是我开始做的,但还没有完成。我的计划是让数组中的每个对象都有一个'selected.month()'属性,它会使用isPreviousMonth有条件地应用不同的样式,并且会查找正确的数字,而不是只使用{{1对于偏移天!

要完成此任务还有很多工作要做 - 尤其是使日期可选并与ng-class集成,但希望这个例子让您了解一种解决模板问题的方法。还有很多其他方法可以做到这一点,但我发现这是最直观的。

扩展程序

要解决有关有多个月的问题,我已经稍微扩展了the plunker

我在指令中添加了一个属性:

~

根据您在属性中指定的月数,将模板修改为ngModel个特定部分:

<date-picker num-months="3"></date-picker>

所以这需要一个月的数组,每个月都有2个属性:片刻和天数。我添加了一些快速而又脏的javascript来生成它,但是我不会把它粘贴在这里,因为几乎可以有更简洁的方法来做到这一点!

请注意,目前我们仍在观看ng-repeat月份的更改,这会导致(可能不需要的)行为,如果您选择的日期不是在第一个月,则日历会重新安排自己。我认为在这种情况下我不会使用<div class="controls"> <button ng-click="prevMonth()"><-</button> <span ng-repeat="month in months" class="month-title"> {{month.moment.format('MMMM')}} </span> <button ng-click="nextMonth()">-></button> </div> <div class="month" ng-repeat="month in months"> <span class="day" ng-repeat="day in month.days"> {{day.number}} </span> </div> ,而只是添加点击事件来处理正确重新绘制日历。

PS 这解决了克隆部分,但没有解决滚动部分。对于滚动,我建议在month数组的任一端添加一个月,然后具有scope.selected条件,这意味着只显示中间月份。然后,您可以利用角度内置的动画(this is a good reference)来使用css滚动/滚动它们。如果您想了解更多信息,请通过我为此问题打开的聊天与我联系。