AngularJS - How to render a partial with variables?

前端 未结 3 886
误落风尘
误落风尘 2020-12-08 11:14

For example, I have a partial in car-list.html, and I want to render it in several places with different collections of cars. Maybe something like this:

<
相关标签:
3条回答
  • 2020-12-08 11:34

    I'd like to offer my solution, which is in a different design.

    The ideal usage for you is:

    <div ng-include-template="car-list.html" ng-include-variables="{ cars: (allCars | onlyNew) }"></div>
    

    ng-include-variables's object is added to the local scope. Therefore, it doesn't litter your global (or parent) scope.

    Here's your directive:

    .directive(
      'ngIncludeTemplate'
      () ->
        {
          templateUrl: (elem, attrs) -> attrs.ngIncludeTemplate
          restrict: 'A'
          scope: {
            'ngIncludeVariables': '&'
          }
          link: (scope, elem, attrs) ->
            vars = scope.ngIncludeVariables()
            for key, value of vars
              scope[key] = value
        }
    )
    

    (It's in Coffeescript)

    IMO, ng-include is a little bit strange. Having access to the global scope decreases its reusability.

    0 讨论(0)
  • 2020-12-08 11:36

    This directive provides 2-way data-binding between the parent scope and renamed "local" variables in the child scope. It can be combined with other directives like ng-include for awesome template reusability. Requires AngularJS 1.2.x

    jsFiddle: AngularJS - Include a partial with local variables


    The Markup

    <div with-locals locals-cars="allCars | onlyNew"></div>
    

    What's going on:

    • This is basically an extension of the ngInclude directive to allow you to pass renamed variables in from the parent scope. ngInclude is NOT required at all, but this directive has been designed to work well with it.
    • You can attach any number of locals-* attributes, which will all be parsed & watched for you as Angular expressions.
      • Those expressions become available to the included partial, attached as properties of a $scope.locals object.
      • In the example above, locals-cars="..." defines an expression that becomes available as $scope.locals.cars.
      • Similar to how a data-cars="..." attribute would be available via jQuery using .data().cars

    The Directive

    EDIT I've refactored to make use of (and be independent of) the native ngInclude directive, and move some of the calculations into the compile function for improved efficiency.

    angular.module('withLocals', [])
    .directive('withLocals', function($parse) {
        return {
            scope: true,
            compile: function(element, attributes, transclusion) {
                // for each attribute that matches locals-* (camelcased to locals[A-Z0-9]),
                // capture the "key" intended for the local variable so that we can later
                // map it into $scope.locals (in the linking function below)
                var mapLocalsToParentExp = {};
                for (attr in attributes) {
                    if (attributes.hasOwnProperty(attr) && /^locals[A-Z0-9]/.test(attr)) {
                        var localKey = attr.slice(6);
                        localKey = localKey[0].toLowerCase() + localKey.slice(1);
    
                        mapLocalsToParentExp[localKey] = attributes[attr];
                    }
                }
    
                var updateParentValueFunction = function($scope, localKey) {
                    // Find the $parent scope that initialized this directive.
                    // Important in cases where controllers have caused this $scope to be deeply nested inside the original parent
                    var $parent = $scope.$parent;
                    while (!$parent.hasOwnProperty(mapLocalsToParentExp[localKey])) {
                        $parent = $parent.$parent;
                    }
    
                    return function(newValue) {
                        $parse(mapLocalsToParentExp[localKey]).assign($parent, newValue);
                    }
                };
    
                return {
                    pre: function($scope, $element, $attributes) {
    
                        // setup `$scope.locals` hash so that we can map expressions
                        // from the parent scope into it.
                        $scope.locals = {};
                        for (localKey in mapLocalsToParentExp) {
    
                            // For each local key, $watch the provided expression and update
                            // the $scope.locals hash (i.e. attribute `locals-cars` has key
                            // `cars` and the $watch()ed value maps to `$scope.locals.cars`)
                            $scope.$watch(
                                mapLocalsToParentExp[localKey],
                                function(localKey) {
                                    return function(newValue, oldValue) {
                                        $scope.locals[localKey] = newValue;
                                    };
                                }(localKey),
                                true
                            );
    
                            // Also watch the local value and propagate any changes
                            // back up to the parent scope.
                            var parsedGetter = $parse(mapLocalsToParentExp[localKey]);
                            if (parsedGetter.assign) {
                                $scope.$watch('locals.'+localKey, updateParentValueFunction($scope, localKey));
                            }
    
                        }
                    }
                };
            }
        };
    });
    
    0 讨论(0)
  • 2020-12-08 11:51

    You can achieve that easily with a directive.

    Something like that:

    angular.module('myModule')
    .directive('cars', function () {
      return {
        restrict: 'E',
        scope: { 'cars': '=data' },
        template: "<div ng-repeat='car in cars'>\n" +
        "  {{car.year}} {{car.make}} {{car.model}}\n" +
        "</div>"
      };
    });
    

    Then you can use it like that:

    <h1>All New Cars</h1>
    <cars data="allCars | onlyNew"></cars>
    
    <h1>All Toyotas</h1>
    <cars data="allCars | make:toyota"></cars>
    

    You can find more info about directives here.

    0 讨论(0)
提交回复
热议问题