Search code examples
javascriptangularjsangular-routingangular-directiveangular-controller

Routing issue with angular directives


I'm trying to setup one of my first angular projects and am having trouble getting to grips with the routing.

On page load I see the initial template that has been set by the preferencesDirective, which is great.

When I click the "Change Template" button I want it to change to another template but nothing happens. If I set the template url's in the $routeProvider to something invalid then I see a 404 error in the debugger which tells me something must be working but nothing happens when the template url is valid.. How do I get it to change correctly?

Thanks.

<div id="PreferencesApp" class="" ng-app="clientPreferencesModule">    
    <preferences-directive factory-settings="clientPreferences"></preferences-directive>
    <a href="#Details">Change Template</a>
</div>


<script>

    var app = angular.module("clientPreferencesModule", ["ngResource", "ngRoute"]);
    //var app = angular.module("clientPreferencesModule", ["ngRoute"]);


    app.config(function ($routeProvider) {        
        $routeProvider.when("/", { controller: "clientPreferencesController", templateUrl: '/AngularTemplates/ClientPreferences/PreferencesTemplate.html' });
        $routeProvider.when("/Preferences/:id", { controller: "clientPreferencesController", templateUrl: '/AngularTemplates/ClientPreferences/PreferencesTemplate.html' });
        $routeProvider.when("/Preferences", { controller: "clientPreferencesController", templateUrl: '/AngularTemplates/ClientPreferences/PreferencesTemplate.html' });
        $routeProvider.when("/Details", { controller: "clientPreferencesController", templateUrl: '/AngularTemplates/ClientPreferences/DetailsTemplate.html' });                
    });



    app.controller('clientPreferencesController', clientPreferencesController);

    clientPreferencesController.$inject = ["$scope", "$resource", "$rootScope", "$http", "$route", "$location"];

    function clientPreferencesController($scope, $resource, $rootScope, $http, $route, $location) {        
        this.model = @Html.Raw(JsonConvert.SerializeObject(Model));        
        $scope.location = $location.path();        
    }

    app.directive('preferencesDirective', preferencesDirective);

    function preferencesDirective() {

        return {
            restrict: 'EA',
            scope:
            {
                factorySettings: '='
            },
            controller: 'clientPreferencesController',
            controllerAs: 'pc',
            bindToController: true,
            templateUrl: '/AngularTemplates/ClientPreferences/PreferencesTemplate.html'
        }
    }

</script>

Solution

  • For routing to work you've to create different views along with its associated controller & then have directive inside that view. And also you'll need ng-view directive in index.html in which all the routes view going to be loaded. And also preferencesDirective should only contain the reusable unique functionality, & the complete app view, so that you can have it different views with different data sets alongside different view components. So, your template can be:

    <div id="PreferencesApp" class="" ng-app="clientPreferencesModule">    
        <a href="#Details">Change Template</a>
        <div ng-view></div>
    </div>
    

    Now for different routes you can have each different controllers or if you want to handle it in one controller the have only one, but different from directive's controller, so it can be,

    app.config(function ($routeProvider) {        
        $routeProvider.when("/", { controller: "viewController", templateUrl: '/AngularTemplates/ClientPreferences/PreferencesTemplate.html' });
        $routeProvider.when("/Preferences/:id", { controller: "viewController", templateUrl: '/AngularTemplates/ClientPreferences/PreferencesTemplate.html' });
        $routeProvider.when("/Preferences", { controller: "viewController", templateUrl: '/AngularTemplates/ClientPreferences/PreferencesTemplate.html' });
        $routeProvider.when("/Details", { controller: "viewController", templateUrl: '/AngularTemplates/ClientPreferences/DetailsTemplate.html' });                
    });
    

    Have preferencesDirective in all these templates. (This will now potentially change the directive's template but you can have changing dom of each view in views's templates & keep directive's template constant) Now in viewController by making use of $routeParams you can check the current route & send different data to preferencesDirective's controller.

    Now if you must want to change directives template conditionally then make use of ng-include inside directive's template.

    function preferencesDirective() {
    
        return {
            restrict: 'EA',
            scope:
            {
                factorySettings: '=',
                templateSrc: '='
            },
            controller: 'clientPreferencesController',
            controllerAs: 'pc',
            bindToController: true,
            templateUrl: '<ng-include src="pc.template()"></ng-include>'
        }
    }
    
    function clientPreferencesController($scope, $resource, $rootScope, $http, $route, $location) {        
        this.model = @Html.Raw(JsonConvert.SerializeObject(Model));        
        $scope.location = $location.path();     
        $scope.template = function(){
            if($scope.templateSrc) {
                return '/AngularTemplates/ClientPreferences/'+ $scope.templateSrc + '.html';
            }
        }
    }
    

    Here share that templateSrc from viewController based on current route.