Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two way data binding is not working in directive

I'm fairly new to AngularJS and it's the first time I'm writing a directive.

I'm trying to make Bootstrap Year Calendar work with AngularJS. It is a jQuery plug-in to show a calendar with appointments.

I've written this directive to create the calendar:

    app.directive('calendarScheduler', [function () {
        return {
            restrict: 'A',
            scope: {
                calendarData: '='
            },
            link: function (scope, element, attrs, ctrl) {
                element.calendar({
                    enableRangeSelection: true,
                    dataSource: scope.calendarData
                });
            }
        }
    }]);

The data is passed to the directive from this controller:

var app = angular.module('App', [])

app.controller('UserCtrl', ['$scope', 
    function($scope) {
        $scope.User = {};
        $scope.User.eventsData = [];

        init();

        $scope.User.addData = function(startDate, endDate) {
            $scope.User.eventsData.push({
                id: 2,
                name: 'Apple Special Event',
                location: 'San Francisco, CA',
                startDate: new Date(2016, 6, 28),
                endDate: new Date(2016, 6, 29)
            });
        };

        function init() {
            $scope.User.eventsData = [
                {
                    id: 0,
                    name: 'Google I/O',
                    location: 'San Francisco, CA',
                    startDate: new Date(2016, 4, 28),
                    endDate: new Date(2016, 4, 29)
                },
                {
                    id: 1,
                    name: 'Microsoft Convergence',
                    location: 'New Orleans, LA',
                    startDate: new Date(2016, 2, 16),
                    endDate: new Date(2016, 2, 19)
                }
            ];
        }
     }]);

And here is the HTML:

<body ng-app="App">
    <div ng-controller="UserCtrl">
        <div
            calendar-scheduler
            id="calendar" 
            class="calendar" 
            calendar-data="User.eventsData">
        </div>
        <button data-ng-click="UserHoliday.addData();">Add Data</button>
    </div>
</body>

Plunker showing the result

Everything works if the data is passed at the creation of the directive, but if I click the button to add more data to the calendar, it does not update the data shown (It should show one new appointment). This also does not show data loaded using $http. I've tried $scope.$apply() to update the $scope, both on controller and directive, but it throws an error "$apply already in progress".

As I've said, I'm really new to AngularJS, and I don't know how to make this work, or if I'm missing something here.

Hope you can help. Thanks.

like image 380
Sergi Avatar asked Oct 17 '22 20:10

Sergi


1 Answers

You only bind the data once, so it will never update. Instead 'watch' the data collection:

app.directive('calendarScheduler', [function () {
    return {
        restrict: 'A',
        scope: {
            calendarData: '='
        },
        link: function (scope, element, attrs, ctrl) {
            function init() {
                element.calendar({
                    enableRangeSelection: true,
                    dataSource: scope.calendarData
                });
            }

            // re-init when data is changed
            scope.$watchCollection("calendarData", function(val) {
                // according to the documentation, data can be updated by doing:
                element.data("calendar").setDataSource(val);
            });

            init();

            scope.$on("$destroy", function() {
                // not sure if this is supported by the library,
                // but is a best practice to prevent memory leaks
                element.calendar("destroy");
            });
        }
    }
}]);
like image 55
devqon Avatar answered Nov 04 '22 20:11

devqon