问题
Given the following service that is meant to create a "dialog" element (i.e. a modal):
app.service('dialog', ['$document', '$compile', '$rootScope',
function($document, $compile, $rootScope) {
var body = $document.find('body');
var scope = $rootScope.$new();
this.createDialog = function() {
var dialogElem = angular.element('<div ng-include="\'/dialog.html\'"></div>');
$compile(dialogElem)(scope);
body.append(dialogElem);
};
}
]);
which can be utilized in a controller like so:
$scope.someFunction = function() {
dialog.createDialog();
};
Is there a way that I can use $compile
or anything else to not have HTML in my service? I'd really prefer to just invoke a directive, so that running createDialog()
immediately injects a directive into my DOM and thus the directive is responsible for linking a new controller and template together. If I'm going about this the wrong way I'm totally open to constructive ideas.
回答1:
Of course you can!, here you go:
app.factory('modalService', function ($document, $compile, $rootScope, $templateCache, $http) {
var body = $document.find('body'),
modals = [];
var service = {
show: function (template, data, modal) {
// The template's url
var url = 'template/modal/' + template + '.html';
// A new scope for the modal using the passed data
var scope = $rootScope.$new();
angular.extend(scope, data);
// Wrapping the template with some extra markup
modal = modal || angular.element('<div class="modal"/>');
// The modal api
var api = {
close: function () {
modal.remove();
scope.$destroy();
modals.splice(modals.indexOf(api), 1);
},
replace: function (template, data) {
return angular.extend(api, service.show(template, data, modal));
}
};
// Adding the modal to the body
body.append(modal);
// A close method
scope.close = api.close;
// Caching the template for future calls
$http.get(url, {cache: $templateCache})
.then(function (response) {
// Wrapping the template with some extra markup
modal.html('<div class="win">' + response.data + '</div>');
// The important part
$compile(modal)(scope);
});
modals.push(modal);
return api;
},
showOrReplaceLast: function (template, data) {
return service.show(template, data, modals.length > 0 ? modals[modals.length - 1] : null);
}
};
return service;
});
Some notes:
- You need to insert the modal somewhere in the DOM, that's why the $document is injected.
- Yes, you can take the modal markup out of here.
- Remember to create new scopes for the dialog and to destroy them ($rootScope.$new).
- This is a WIP, I hope it's clear enough.
回答2:
You could try this as below, just to render your ng-include before opening the dialog
app.service('dialog', ['$http', '$compile', '$q', '$templateCache'
function($http, $compile, $q, $templateCache) {
this.compileInclude = function(scope, url) {
var deferred = $q.defer();
$http.get(url, {cache : $templateCache}).then(function(response){
deferred.resolve($compile(response.data)(scope));
});
return deferred.promise;
};
}
]);
From the controller write as below
dialog.compileInclude($scope, 'dialog.html').then(function(){
// open dialog here
});
来源:https://stackoverflow.com/questions/26109658/can-i-use-compile-in-an-angular-service-directly-on-a-templateurl-instead-of-on