Reputation: 438
I'm using RequireJS to load JS, but the HTML partial won't wait for the required JS directives....
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
Upvotes: 1
Views: 709
Reputation: 438
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.
Upvotes: 1