AngularJS - Include a partial with local variables.

AngularJS - Render a Template with Variables. 2-way data binding.

by Collin Donahue-Oponski

HTML

<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.5.1/underscore-min.js"></script>
<!-- SEE http://stackoverflow.com/questions/17863732/angularjs-how-to-render-a-partial-with-variables -->
<div ng-app="cars">
    <div ng-controller="CarsControl">

        <h1>All Cars</h1>
        <div ng-repeat="car in allCars">
            <input ng-model="car.model" type="text" />
            <a href="javascript://" ng-click="removeCar(car)">x</a>
        </div>
        <a href="javascript://" ng-click="addCar()">add a car</a>
        
        <h1>Car Models that start with B</h1>
        <div with-locals ang-include="'car-list.html'" 
            locals-cars="allCars | startsWithB:'model'"></div>

        <h1>Car Models that start with C</h1>
        <div with-locals ang-include="'car-list.html'" 
            locals-cars="allCars | modelStartsWithC"></div>

    </div>
</div>

CSS

</style> <!-- Ugly Hack to make remote files preload in jsFiddle --> 
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular.min.js"></script>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.19/angular-sanitize.min.js"></script>
<style>

JavaScript

function CarsControl($scope) {
    $scope.allCars = [{
        model: 'Bart'
    }, {
        model: 'Cart'
    }, {
        model: 'Dart'
    }];
    
    $scope.addCar = function() {
        $scope.allCars.push({});
    };
    $scope.removeCar = function(car) {
        var i = _($scope.allCars).indexOf(car);
        if (i >= 0) $scope.allCars.splice(i, 1);
    };
    
//    $scope.$watch("allCars", function(newValue) {
//        $scope.carsStartingWithB = $scope.$eval("allCars | startsWithB:'model'");
//    }, true);
}

angular.module('withLocals', [])
    .directive('withLocals', function($parse) {
        return {
            scope: true,
            /* DEMO ONLY: use a custom template for the directive instead of the ngInclude directive */
            template: '<ul><li ng-repeat="car in locals.cars">{{car.model}} <input ng-model="car.model" type="text"></li></ul>',
            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...