We were facing this issue several days before. At that time, we were introducing Angular into our HTML5 based mobile family photo social application Family Snap. It's maintained by www.uhella.com.
During the restructure, I moved the dojo code into directive inline, it works well. The calendar_month_datepicker (dojox.mobile.SpinWheelDatePicker)
was successfully injected by dijit to be a huge Div then.
After that, I want to separate it into individual html file as template, because html editor will understand my html code better. So I modify the code as following:
Familysnap/directive/homepickdata.js
'use strict';
/* Directives */
FamilySnapModule.directive('homePickdata', function() {
return {
restrict: 'EAC',
replace: true,
transclude: true,
templateUrl: 'Familysnap/templates/homePickdata.html'
//template: '<div id="calendar_month_datepicker" data-dojo-type="dojox.mobile.SpinWheelDatePicker" data-dojo-props=\'slotOrder: [0,1,2], monthPattern: "MM", dayPattern: "dd", align: "center"\'></div>'
};
});
Familysnap/templates/homePickdata.html
<div id="calendar_month_datepicker" data-dojo-type="dojox.mobile.SpinWheelDatePicker" data-dojo-props='slotOrder: [0,1,2], monthPattern: "MM", dayPattern: "dd", align: "center"'></div>
Familysnap/modules/dataPicker.js
require([
…
], function(dom, domStyle, domAttr, on, ready, registry, JSON, string,
ListItem, array, request, domClass, query, domProp, domConstruct, tap, swipe, Uuid, generateRandomUuid,
Pane, SpinWheelDatePicker, win, Opener, Heading, ToolBarButton, SwapView) {
function FamilySnapMonthToday()
{
…
setTimeout(function(){
registry.byId("calendar_month_datepicker").set("values", [global_calendar_current_year, global_calendar_current_month + 1, global_calendar_current_date]);
}, 500);
…
}
function FamilySnapMonthDone()
{…
var values = registry.byId("calendar_month_datepicker").get("values");
…
}
ready(function(){
…
on(dom.byId("calendar_month_done_btn"), "click", FamilySnapMonthDone);
…
});
});
After this modification, the calendar_month_datepicker (dojox.mobile.SpinWheelDatePicker) was not injected by dijit. It just injected by angular compiler. And the “registry.byId("calendar_month_datepicker")” will always return null.
I finally figured out the load sequence between template and templateUrl is different in angular compiler by chrome source code debug tools (Debugging-in-PhoneGap ).
First of all, I set up break point on my directive.
At the time code paused on my break point.
Familysnap/directive/homepickdata.js
'use strict';
/* Directives */
FamilySnapModule.directive('homePickdata', function() {
return {
restrict: 'EAC',
replace: true,
transclude: true,
templateUrl: 'angular/templates/homePickdata.html'
//template: '<div id="calendar_month_datepicker" data-dojo-type="dojox.mobile.SpinWheelDatePicker" data-dojo-props=\'slotOrder: [0,1,2], monthPattern: "MM", dayPattern: "dd", align: "center"\'></div>'
};
});
The directive “home-pickdata” in both version is not injected. It's what we expect.
<div home-pickdata></div>
The different is here:
function bootstrap(element, modules) {
var doBootstrap = function() {
element = jqLite(element);
if (element.injector()) {
var tag = (element[0] === document) ? 'document' : startingTag(element);
throw ngMinErr('btstrpd', "App Already Bootstrapped with this Element '{0}'", tag);
}
modules = modules || [];
modules.unshift(['$provide', function($provide) {
$provide.value('$rootElement', element);
}]);
modules.unshift('ng');
var injector = createInjector(modules);
injector.invoke(['$rootScope', '$rootElement', '$compile', '$injector', '$animate',
function(scope, element, compile, injector, animate) {
scope.$apply(function() {
element.data('$injector', injector);
compile(element)(scope);
});
}]
);
return injector;
};
After the compile(element)(scope), the template version of directive is injected as following:
<div id="calendar_month_datepicker" data-dojo-type="dojox.mobile.SpinWheelDatePicker" data-dojo-props='slotOrder: [0,1,2], monthPattern: "MM", dayPattern: "dd", align: "center"'></div>
But the templateUrl version is still:
<div home-pickdata></div>
Even after the angularInit:
//try to bind to jquery now so that one can write angular.element().read()
//but we will rebind on bootstrap again.
bindJQuery();
publishExternalAPI(angular);
jqLite(document).ready(function() {
angularInit(document, bootstrap);
});
})(window, document);
The templateUrl version is still:
<div home-pickdata></div>
After this hook, the dojo injector will take care of all dojo tags, but at that time, the templateUrl version of directive is still not injected by Angular.
So dojo/dijit don’t know the ID “calendar_month_datepicker”. This explain why registry.byId(“calendar_month_datepicker”) return NULL in our code.
I am not familiar with dojo injector. I believe there's way to make dojo work together with angular templateUrl directive by some magic.
By reading the answer from Dimitri M and tik27, I update the code. We need call "dojo/parser" manually to inject our widget.
Change data-dojo-type to data-familysnap-type.
<div id="calendar_month_datepicker" data-family-type="dojox.mobile.SpinWheelDatePicker" data-dojo-props='slotOrder: [0,1,2], monthPattern: "MM", dayPattern: "dd", align: "center"'></div>
and call parser on ready()
require(["dojo/parser"],function(dom,registry,parser)){
ready() {
parser.parse({scope: "familysnap"});
...
}
}
Then the calendar_month_datepicker was injected by dijit. We can successfully call
registy.byId('calendar_month_datepicker')