0

I wanted to create a datepicker using jqueryUi and angularjs. I want to get the datepicker value from all my controllers. For that, I created a factory :

App.factory "selectedDate", ['$rootScope', ($rootScope) ->
  selectedDates = {}
  selectedDates.from = moment()

  selectedDates.nextPeriod = ->
    this.from.add('days', 1);

  selectedDates.previousPeriod = ->
    this.from.subtract('days', 1);

  return selectedDates
]

And my controllers :

App.controller "DashboardDatePickerCtrl", ['$scope', 'selectedDate', ($scope,selectedDate) ->

  $scope.nextPeriod = () ->
    selectedDate.nextPeriod()

  $scope.previousPeriod = () ->
    selectedDate.previousPeriod()

  $scope.date = selectedDate.from
]

App.controller "otherCtrl", ['$scope', 'selectedDate', ($scope,selectedDate) ->
  $scope.date = selectedDate.from
]

My html (haml) :

.row-fluid{ "ng-controller" => "DashboardDatePickerCtrl" }
  .span4.offset5
    %span.fui-arrow-left.right10.top5.font-large.pointer{ "ng-click" => "previousPeriod()"}
    .control-group.inline
      .input-prepend.input-datepicker
        %button.btn{:type => "button"}
          %span.fui-calendar
        %input#datepicker-01.span2{:type => "text", "ng-model" =>"date", "datepicker" => ""}

    {{ date }}

    %span.fui-arrow-right.left10.font-large.pointer{ "ng-click" => "nextPeriod()"}

  .span3
    .btn-group.choose-granularity{"data-toggle" => "buttons-radio"}
      %button#by_4h.btn.btn-primary.one_month One month
      %button#by_1h.btn.btn-primary.one_week One week
      %button#by_5m.btn.btn-primary.one_day.active One day

.row-fluid
  .span12{ "ng-controller" => "otherCtrl" }
    %h6 An other ng controller
    %p
      {{ date.format("DD MMM, YYYY") }}

And to finish, my datepicker directive :

App.directive('datepicker', (selectedDate) ->
  return {
    restrict: 'A'
    require : 'ngModel'
    link : (scope, element, attrs, ngModelCtrl) ->
      $ ->
        element.datepicker({
          showOtherMonths: true
          selectOtherMonths: true
          dateFormat: "d MM, yy"
          yearRange: '-1:+1'
          onSelect: (date) ->
            selectedDate.from = moment(date)
            scope.$apply();
        })
    }
);

The fact is, when I select a date in my datepicker, the date on the "otherCtrl" or "DashboardDatePickerCtrl" does not change.

I thought that update the value of an attribute of my factory will update all other variables pointing to this variable.

What did I miss?

JSFIDDLE: http://jsfiddle.net/9HZdm/6/

Sebastien
  • 6,640
  • 14
  • 57
  • 105

1 Answers1

2

The problem is that you lose the reference to the .from property. As soon as your otherController and DashboardDatePickerCtrl starts, they get a reference to the selectedDate.from. But in your date change handler, you are changing the .from to another object in memory (selectedDate.from = ...), but the controllers are still pointing at the old one, now lost in memory for ever (quite dramatic).

The easy way to fix it, is to expose the entire selectedDate in the controller, and bind to its subproperty. This way, you will change the .from, but will not change the .selectedDate.

In your controller you should go with $scope.date = selectedDate; instead of $scope.date = selectedDate.**from** and in your bind, you should go as date.from.format(...). This will solve the problem.

If you mind a suggestion, there is also UI-Bootstrap calendar directive.

I've talked a little about it at this answer.

Community
  • 1
  • 1
Caio Cunha
  • 23,326
  • 6
  • 78
  • 74
  • Is it possible for you to update my fiddle? I try to apply what you are talking about but no success...Thx in advance – Sebastien Jul 11 '13 at 13:51
  • An one more question, how can I watch the change of "selectedDate" in my controllers from my directive "datepicker"?. When we click on next-period, I want to update my datepicker's input value. – Sebastien Jul 11 '13 at 14:06
  • This is a good question itself. I think it's good to discuss over it. But as you're changing the internal state of an object, and not the object reference itself, maybe the best choice is to not expose the `selectedDate.from` object, but instead only expose methods that would add (or subtract) values from the object and expose the result in some variable or dispatch an event that you would be able to listen to. I'll take some time to think about it, and will try to answer back. In the mean while, if you come up with a good approach, please let me know. – Caio Cunha Jul 12 '13 at 14:12