Use Angular Directive attributes in its template

时光毁灭记忆、已成空白 提交于 2019-12-04 22:24:13

You can pull the attributes out and place them into the scope of the directive like this:

angular.module('myApp', []).
directive('myTooltip', function ($log) {
    // allowed event listeners
    var allowedListeners = ["click"];
    return {
        restrict: 'A',
        template:   '<div class="tooltip-title">{{tooltipTitle}}</div>' +
                    '<div class="tooltip-content">' +
                    '{{tooltipContent}}</div>',
        scope: {
            tooltipTitle: '@tooltipTitle',
            tooltipContent: '@tooltipContent'
        },
        link: function (scope, elm, attrs) {
            if (allowedListeners.indexOf(attrs.myTooltip) != -1) {
                elm.bind(attrs.myTooltip, function () {
                    $log.info('clicked');
                });
            }

        }
    };
});

Here is fiddle: http://jsfiddle.net/moderndegree/f3JL3/

This question has already been answered, but I'm going to share my Angular code aswell, as this is one area where it's often useful to see a few working examples.

I have a few webpages, each with their own Angular controller, and I wanted a way to have one "Please Wait" popup on each page, which would appear when any of the pages called an HTTP GET or POST web service.

To do this, each of my webpages contains this line:

<please-wait message="{{LoadingMessage}}" ></please-wait>

...which is bound to a $scope in that page's controller...

$scope.LoadingMessage = "Loading the surveys...";

Here's the code for my <please-wait> directive:

myApp.directive('pleaseWait',  
    function ($parse) {
        return {
            restrict: 'E',
            replace: true,
            scope: {
                message: '@message'
            },
            link: function (scope, element, attrs) {
                scope.$on('app-start-loading', function () {
                    element.fadeIn(); 
                });
                scope.$on('app-finish-loading', function(){
                    element.animate({
                        top: "+=15px",
                        opacity: "0"
                    }, 500);
                });
            },
            template: '<div class="cssPleaseWait"><span>{{ message }}</span></div>'
        }
    });

Notice how it picks up the message attribute ({{LoadingMessage}} in this example) and can display its value in the directive's template.

(That's actually the only part of my answer which directly answers this question, but read on, for a few more tips'n'tricks...)

Now, the cool part is that each of my controllers calls an Angular data service whenever it wants to load or save any data from/to a web service.

   $scope.LoadAllSurveys = function () {
        DataService.dsLoadAllSurveys($scope).then(function (response) {
            //  Success
            $scope.listOfSurveys = response.GetAllSurveysResult;
        });
   }

The dsLoadAllSurveys function looks like this...

myApp.webServicesURL = "http://localhost:15021/Service1.svc";

myApp.factory('DataService', ['$http', 'httpPostFactory', 'httpGetFactory',
    function ($http, httpPostFactory, httpGetFactory) {

        var dsLoadAllSurveys = function (scope)
        {
            //  Load all survey records, from our web server
            var URL = myApp.webServicesURL + "/getAllSurveys";
            return httpGetFactory(scope, URL);
        }

        return {
            dsLoadAllSurveys: dsLoadAllSurveys
        }
    }]);

And, crucially, all "GET" web service calls go via the following function, which displays the Please Wait control for us... then makes it go away when the service has completed.

myApp.factory('httpGetFactory', function ($http, $q) {
    return function (scope, URL) {
        //  This Factory method calls a GET web service, and displays a modal error message if something goes wrong.
        scope.$broadcast('app-start-loading');          //  Show the "Please wait" popup

        return $http({
            url: URL,
            method: "GET",
            headers: { 'Content-Type': undefined }
        }).then(function (response) {
            scope.$broadcast('app-finish-loading');     //  Hide the "Please wait" popup
            if (typeof response.data === 'object') {
                return response.data;
            } else {
                // invalid response
                return $q.reject(response.data);
            }
        }, function (errorResponse) {
            scope.$broadcast('app-finish-loading');     //  Hide the "Please wait" popup

            //  The WCF Web Service returned an error.  
            //  Let's display the HTTP Status Code, and any statusText which it returned.
            var HTTPErrorNumber = (errorResponse.status == 500) ? "" : "HTTP status code: " + errorResponse.status + "\r\n";
            var HTTPErrorStatusText = errorResponse.statusText;

            var message = HTTPErrorNumber + HTTPErrorStatusText;

            BootstrapDialog.show({
                title: 'Error',
                message: message,
                buttons: [{
                    label: 'OK',
                    action: function (dialog) {
                        dialog.close();
                    },
                    draggable: true
                }]
            });

            return $q.reject(errorResponse.data);
        });
    };
});

What I love about this code is that this one function looks after displaying/hiding the "Please wait" popup, and if an error occurs, it also looks after displaying the error message (using the excellent BootstrapDialog library), before returning the error result back to the caller.

Without this factory function, each time one of my Angular controllers would call a web service, it would need to show, then hide, the "Please wait" control, and check for errors.

Now, I can just call my web service, and leave it to inform the user if something goes wrong, otherwise I can assume it's all worked, and process the results.

This allows me to have much simpler code. Remember how I called that web service:

   DataService.dsLoadAllSurveys($scope).then(function (response) {
        //  Success
        $scope.listOfSurveys = response.GetAllSurveysResult;
    });

That code looks as though it's not doing any error-handling, whereas actually, it's all looked after behind the scenes in one place.

I'm still getting the hang of factories and data services with Angular, but I think this is a stonking example of how they can help.

Hope this made sense, and helps.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!