Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Best Practices for templateUrl and ngInclude URLs #839

Open
p0lar-bear opened this issue Jun 5, 2017 · 3 comments
Open

Best Practices for templateUrl and ngInclude URLs #839

p0lar-bear opened this issue Jun 5, 2017 · 3 comments

Comments

@p0lar-bear
Copy link

I'm surprised at, with how much this guide pushes modularity in AngularJS, that there is nothing in it that suggests how an app should generate the URLs for ngInclude calls and directive/component templateUrls. Because manually specifying such paths as you do in various examples detracts from modularity and expects the specified file to be in a very specific place relative to the base URL.

For example, relative to my app's index.html, my Angular source code is in mysite/js/myNg/, and my compiled AngularJS scripts will sit in mysite/scripts.js (Angular frontend sitting on top of a SilverStripe PHP backend, mysite contains all non-framework code as a practice of SilverStripe).

If I were to ditch SilverStripe and move my UI to a different platform, or simply place this UI module on a different server by itself, I would have to go through all of my files and manually change each URL to point to the correct paths if the new framework discouraged the same module directory structure as Silverstripe, or if I decide to plop the scripts in a different place altogether.

There are a couple different routes I can think of right here and now to address this, if this is something that the guide should cover.

  1. Specify an APP_DIR constant in the module config that contains the relative-to-base path to the module code, and then inject this constant into any directive or controller that will need to call in templates or partials. This will make it so there is only one file that needs to be edited if the code base is moved, and module authors can document this as something that needs to be changed.
  2. Use a Grunt/Gulp build task (e.g. grunt-angular-templates to get all .html files in a module, giving them to $templateCache.
@MarcLoupias
Copy link

ngInclude should be avoided. Use a component instead.

I agree with you about templateUrl and constants but you cannot use angular.module.constant because you cannot declare the component factory method when writing a component. You are limited to the definition object.

You have to do that :

angular
    .module('sales.widgets')
    .component('acmeSalesCustomerInfo', {
        templateUrl: 'app/sales/widgets/acme-sales-customer-info.html',
        bindings: {
            data: '<',
            onWhateverClick: '&'
        },
        controller: salesCustomerInfo
    });

    function salesCustomerInfo(/* component controller injections are here */) {
        /* implementation details */
    }

You cannot do that :

angular
    .module('sales.widgets')
    .component('acmeSalesCustomerInfo', acmeSalesCustomerInfoComponent);

    acmeSalesCustomerInfoComponent.$inject = ['TEMPLATES_URL'];

    function acmeSalesCustomerInfoComponent(TEMPLATES) {
        return {
            templateUrl: TEMPLATES + '/acme-sales-customer-info.html',
            bindings: {
                data: '<',
                onWhateverClick: '&'
            },
            controller: salesCustomerInfo
        };
    }

    function salesCustomerInfo(/* component controller injections are here */) {
        /* implementation details */
    }

Anyway you could use external file with global var as constants and used IIFE to inject them, example :

(function (angular, TEMPLATES_URL) {
    'use strict';
    
    angular
        .module('sales.widgets')
        .component('acmeSalesCustomerInfo', {
            templateUrl: TEMPLATES_URL.SALES.WIDGETS + '/acme-sales-customer-info.html',
            bindings: {
                data: '<',
                onWhateverClick: '&'
            },
            controller: salesCustomerInfo
        });

    function salesCustomerInfo() {
        /* implementation details */
    }

})(angular, TEMPLATES_URL);

Something like that.

@p0lar-bear
Copy link
Author

In that case, I feel it would be much more prudent to have HTML template files compiled into calls to $templateCache.put() in a run block, seeing how components cannot have a factory. I've experimented with this approach since I posted and I find it to be easy and fitting for the style being put forth.

In general, you point grunt-angular-templates at a file list, and it generates an Angular run block that calls $templateCache.put() with each template file path and its contents. So it finds app/sales/widgets/acme-sales-customer-info.html at compile time, and makes it so your app always has app/sales/widgets/acme-sales-customer-info.html available when the module is included, even if the file doesn't exist on the server.

@p0lar-bear
Copy link
Author

...I didn't mean to close this issue with that comment. Sorry.

@p0lar-bear p0lar-bear reopened this Jun 9, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants