Dismiss
Announcing Stack Overflow Documentation

We started with Q&A. Technical documentation is next, and we need your help.

Whether you're a beginner or an experienced developer, you can contribute.

Sign up and start helping → Learn more about Documentation →

I'm using RequireJS to load JS, but the HTML partial won't wait for the required JS directives....

  1. Start loading JS
  2. Render HTML (w/ directives)
  3. Finish JS then define directives (Oops too late, already rendered HTML)

I'm allowing "plug-ins" in my SPA that allow me to drop in new entities (HTML+JS). The HTML is loaded via controller (in this case by "$templateFactory.fromUrl()" inside the directive's linking), and the corresponding JS is included from within that HTML partial.

function inputFrequencyDirective($templateFactory, $compile) {
    return {
        restrict: 'E',
        scope: {},
        bindToController: {
            frequency: '=ngmodelFrequency',
        },
        compile: function CompilingFunction(element, attrs) {
            return function LinkingFunction($scope, $element, $attrs) {
                var frequency = $scope.vm.frequency;
                var type = frequency.type;
                var promise = $templateFactory.fromUrl(type + ".html");
                promise.then(function (template) {
                    var e = $compile(template)($scope);
                    $element.replaceWith(e);
                });
            };
        },

The HTML partial (Weekly.html):

<script type="text/javascript">
    // Async load "weekly.js"
    require(['angular', 'weekly'], function (angular) {
        console.log("weekly.html require complete");
    });
</script>
<h1>Weekly</h1>
<div>
    <frequency-type-selector ngmodel-type="vm.frequency.type"></frequency-type-selector>
    <div><label>Every <frequency-weekly-input-day ngmodel-day="vm.frequency.day"></frequency-weekly-input-day> (day of week)</label></div>
</div>

The JS included (weekly.js):

function (angular) {
    var app = angular.module('myApp');
    app.lazy.directiveRegister('frequencyWeeklyInputDay', [function () {
    [...]

The solution is simple and works great with the standard frameworks, but using async RequireJS, I've got a sequencing issue. If I switch my frequency type to "daily" then back to "weekly", the HTML renders properly because the directive in weekly.js DID get registered, but just too late for the first Weekly.html render.

I essentially want to "wait for the require to finish" before the script finishes (thus delaying the HTML render). The best way might be to surround the HTML with an element utlizing "ng-if", and enable the HTML by "truifying the ng-if" from within the Weekly.html's script "require" block. That should make the element appear properly rendered when the load is complete.

I'd like to know if the "ng-if" idea is reasonable and how to do it from within the non-angular script block. I don't know how to get a reference to the proposed element with the ng-if, or how to do that safely from other instances of this potentially shared control.

Proposed "concept":

<script type="text/javascript">
    var someflag = false;
    require(['angular', 'weekly'], function (angular) {
        someflag = true;
    });
</script>
<h1>Weekly</h1>
<div ng-if="someflag">
    <frequency-type-selector ngmodel-type="vm.frequency.type"></frequency-type-selector>
    <div><label>Every <frequency-weekly-input-day ngmodel-day="vm.frequency.day"></frequency-weekly-input-day> (day of week)</label></div>
</div>

I'm using current versions: angular 1.4.8, uiRouter 0.2.17, requireJS 2.2.0

share|improve this question
    
have a look at this repo, it works much simpler. github.com/ocombe/ocLazyLoad – z.a. Mar 29 at 18:24
    
Here's the full Plunk plnkr.co/edit/76feCbf15aJhYeJkS8VZ – AAron Mar 29 at 19:03
    
The deleted comment had a nice polling loop. I'm trying to wrap my mind around the fact that I've got a file with both HTML and JS... and I need to delay the HTML itself. Its nice to use timeouts/events, but I would truly need to block until the RequireJS function sets the flag. I'd really like to use events here and enable that HTML block (ng-if), but I don't know how to reach it from standard Javascript.(Meanwhile I'm looking at that ocLazyLoad to see if it will offer comparable simple solution) – AAron Mar 29 at 20:13
    
In the ocLazyLoad examples, it looks like I'd have to declare/load all the dependencies (ex: manifest) to load them all beforehand. Notice in my Plunk, I want to let the HTML partial be the entry point, and it will know and handle its own dependencies with standard require/angular frameworks. – AAron Mar 29 at 20:20
    
honestly, registering directives lazily is a waste of time I think. sure you might wanna lazy load libraries, and you should, eg. if you use d3.js only in one page or directive. why not. perhaps you can modularize your code and lazy load even modules that contains many directives. – z.a. Mar 29 at 20:20

I tried many things to block/event/semaphore on the async loading of RequireJS, but couldn't get it to work.

Then I made the whole solution synchronous by putting an IIFE in the included partial. I got it all to work by enacting some other changes too (ex: simplified the including directive to use ng-include, removed my script handling directive to let jquery do it, ...).

Here is the final Plunk that works synchronously lazily loading HTML/script partials: https://plnkr.co/edit/76feCbf15aJhYeJkS8VZ

<script type="text/javascript">
(function (angular) {
    [..]
})(angular);
</script>
<h1>Weekly</h1>
<div>
    <frequency-type-selector ngmodel-type="vm.frequency.type"></frequency-type-selector>
    <div><label>Every <frequency-weekly-input-day ngmodel-day="vm.frequency.day"></frequency-weekly-input-day> (day of week)</label></div>
</div>

I hope you find this example useful.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.