Skip to content

AngularJS: Example Deckster Directives

baileyreed39 edited this page Aug 17, 2016 · 8 revisions

Angular Directives for Deckster

A custom Angular directive will allow you to insert one piece of HTML into another via an HTML tag or attribute. See here for an explanation of Angular directives. Deckster uses directives to place the deck into the HTML of your app. This page explains how to write directives for the deck, card, and pop-out.

Complete Example

See the directive file for the Github Pages' Angular example for a complete example of these directives.

Deckster Deck

Define your custom directive and call it 'decksterDeck'. This is the directive you will instantiate in your own HTML.

angular.module('app').directive('decksterDeck', function ($parse, $timeout) {

Then, within this function, you might want to define your defaults for Gridster, the jQuery plug-in that Deckster is based on. These defaults can be overridden as you configure each deck, but they should be defined at least in once of those places. See Gridster Documentation for additional options.

    var defaults = {
        gridsterOpts: {
            max_cols: 4, // max columns
            widget_margins: [10, 10], // x, y margins between each card
            widget_base_dimensions: ['auto', 250], // x, y dimensions of rows and columns. 'auto' will set width to be responsive to page size
           responsive_breakpoint: 850 // responsiveness of when cards change position when one card is dragged
        }
    };

Then define the directive itself:

    return {
        restrict: 'EA', // restricts directive to be usable via element tag and attribute
        replace: true,
        scope: { // sets two-way binding between parent and isolated scope for 'deck' and 'initialized' variables
            deck: '=',
            initialized: '='
        },

Reference a template file for your Deckster deck

        templateUrl: '/partials/decksterDeck.html', // insert path to your template file

Within that template file (decksterDeck.html), include the following HTML:

<div class="deckster-deck-wrapper">
    <div class="deckster-deck" deck-options="deck">
        <deckster-card ng-repeat="cardOpts in deck.cards" card-options="cardOpts"></deckster-card>
    </div>
</div>'

These controller functions will properly set up your Deckster deck:

       controller: function($scope) {
            $scope.deckInitialized = false;

            $scope.$on('deckster:resize', function () {
                if ($scope.deckster) {
                    $timeout(function () {
                        $scope.deckster.$gridster.recalculate_faux_grid();
                    });
                }
            });

            this.addCard = function (card, callback) {
                $scope.deckster.addCard(card, function (card) {
                    if (callback) callback(card);
                });
            };

            this.init = function (element, opts) {
                $scope.deckster = $(element).deckster(opts).data('deckster');
                $scope.deckInitialized = true;
            };
        },
        link: function (scope, element, attrs, ctrl) {
            var deckOptions = $.extend(true, {}, defaults, scope.deck);
            var $deckEl = $(element).find('.deckster-deck');

            scope.$watch('initialized', function(init) {
                if (init && !scope.deckInitialized) {
                    ctrl.init($deckEl, deckOptions);
                }
            });

            scope.$on('$destroy', function() {
                scope.deckster.destroy();
                scope.deckInitialized = false;
            });
        }
    };
})

Deckster Card

The instantiation of the Deckster Deck directive should call the Deckster Card directive using ng-repeat.

angular.module('app').directive('decksterCard', function ($parse, $q, $http, $timeout) {
        return {
            restrict: 'E',
            require: ['^decksterDeck', 'decksterCard'],
            controller: function ($scope, $compile) {

Within the controller, there are several default functions that you may define if you wish. None of these are necessary for basic Deckster functionality.

                // Default summaryContentHtml function
                this.getSummaryContent = function (card, cb) {
                  $timeout(function() {
                    cb($compile('<div></div>')($scope));
                  });
                };
                
                // Default detailsContentHtml function
                this.getDetailsContent = function (card, cb) {
                  $timeout(function() {
                    cb($compile('<div></div>')($scope));
                  });
                };

                // Default leftControlsHtml function
                this.getLeftControlsContent = function (card, cb) {
                    $timeout(function() {
                        cb($compile('<div></div>')($scope));
                    });
                };

                // Default rightControlsHtml function
                this.getRightControlsContent = function (card, cb) {
                    $timeout(function() {
                        cb($compile('<div></div>')($scope));
                    });
                };

                // Default centerControlsHtml function
                this.getCenterControlsContent = function (card, cb) {
                    $timeout(function() {
                        cb($compile('<div></div>')($scope));
                    });
                };

                this.onReload = function (card) {
                    console.log('card reloaded', card);
                };

                this.onResize = function (card) {
                    console.log('card resized', card);
                };

                this.onExpand = function (card)  {
                    console.log('card expanded', card);
                };

                this.scrollToCard = function () {
                    $scope.card.scrollToCard();
                };

                this.toggleCard = function () {
                    $scope.card.hidden ? $scope.card.showCard() : $scope.card.hideCard();
                };

This function IS necessary, and will set up your defaults as well as create the card itself.

                this.setUpCard = function (cardOpts) {
                    if(!cardOpts.summaryViewType && !cardOpts.detailsViewType) {
                        cardOpts.summaryContentHtml = cardOpts.summaryContentHtml || this.getSummaryContent;
                        cardOpts.detailsContentHtml = cardOpts.detailsContentHtml || this.getDetailsContent;
                        cardOpts.onResize = cardOpts.onResize || this.onResize;
                        cardOpts.onReload = cardOpts.onReload || this.onReload;
                    }

                    cardOpts.showFooter = false;
                    cardOpts.leftControlsHtml = this.getLeftControlsContent;
                    cardOpts.rightControlsHtml = this.getRightControlsContent;
                    cardOpts.centerControlsHtml = this.getCenterControlsContent;

                    $scope.$on('deckster-card:scrollto-' + cardOpts.id, this.scrollToCard);
                    $scope.$on('deckster-card:toggle-' + cardOpts.id, this.toggleCard);

                    return cardOpts;
                };
            },

The link function will then set up the event listeners.

            link: function (scope, element, attrs, ctrls) {
                var deckCtrl = ctrls[0];
                var cardCtrl = ctrls[1];

                var cardOpts = $parse(attrs.cardOptions || {})(scope);

                scope.$watch('deckInitialized', function (initialized) {
                    if (initialized) {
                        deckCtrl.addCard(cardCtrl.setUpCard(cardOpts), function (card) {
                            scope.card = card;

                            // When the deck is resize resize this card as well
                            scope.$on('deckster:resize', function () {
                                // TODO code to resize cards
                            });

                            scope.$on('deckster:redraw', function () {
                                $timeout(function () {
                                    // TODO code to redraw cards
                                });
                            });
                        });
                    }
                });
            }
        };
    })

Deckster Pop-out

This directive should configure the Deckster pop-out functionality, if you wish you use that.

angular.module('app').directive('decksterPopout', ['$injector', '$compile', '$http', 'Deckster', function($injector, $compile, $http, Deckster) {
        return {
            restrict: 'E',
            link: function(scope, element) {
                var cardId, section;

                var $routeParams = $injector.get('$routeParams');
                cardId = $routeParams.id;
                section = $routeParams.section;


                var getSummaryTemplate = function(cardConfig, cb) {
                    // Not using the cardConfig here but you could use it to make request
                    $http.get('partials/testSummaryCard.html').success(function(html) {
                        if (cb) cb($compile(html)(scope));
                    });
                };

                var getDetailsTemplate = function(cardConfig, cb) {
                    // Not using the cardConfig here but you could use it to make request
                    $http.get('partials/testDetailsCard.html').success(function (html) {
                        if (cb) cb($compile(html)(scope));
                    });
                };

                // Get card config from server or angular constants using cardId
                var cardConfig =  {
                    title: 'Photos',
                    id: 'photoCard',
                    summaryContentHtml: getSummaryTemplate,
                    detailsContentHtml: getDetailsTemplate,
                    position: {
                        size_x: 1,
                        size_y: 1,
                        col: 1,
                        row: 1
                    }
                };

                Deckster.generatePopout(element, cardConfig, section);
            }
        };
    }]);

Clone this wiki locally