在 angular 1.6 中以编程方式加载组件
Load component programmatically in angular 1.6
我有一个 AngularJS 1.6 应用程序,它有一个小部件部分。
小部件部分一行包含 3 个最终用户可以自行配置的小部件。他得到了所有可用小部件的列表,他可以选择要放置的小部件和位置。
每个小部件都是一个像这样初始化的组件:
(
function(angular) {
function Module1Controller() {
var vm = this;
// other stuff here
}
angular.module("app")
.component(
"module1", {
controller: Module1Controller,
templateUrl: 'module1.html'
}
);
}
)(angular)
现在,由于用户可以 select 在特定位置呈现哪个小部件,因此该数据来自网络服务。
根据从 WS 收到的数据,我需要能够 "activate" 一个组件和 "deactivate" 所有其他组件。
我的第一个想法是做这样的事情:
控制器:
(
function(angular) {
function ModulesController() {
var vm = this;
vm.firstModule = 1;
vm.secondModule = 1;
vm.thirdModule = 1;
vm.availableModules = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
}
angular.module("app")
.controller(
"ModulesController",
[
ModulesController
]
);
}
)(angular)
查看:
<div class="container-fluid" ng-controller="ModulesController as c">
<div class="row">
<div class="col-xs-4"> <!-- third widget area -->
<module-1 ng-if="c.firstModule == 1"></module-1>
<module-2 ng-if="c.firstModule == 2"></module-2>
<module-3 ng-if="c.firstModule == 3"></module-3>
<module-4 ng-if="c.firstModule == 4"></module-4>
<module-5 ng-if="c.firstModule == 5"></module-5>
<module-6 ng-if="c.firstModule == 6"></module-6>
<module-7 ng-if="c.firstModule == 7"></module-7>
<module-8 ng-if="c.firstModule == 8"></module-8>
<module-9 ng-if="c.firstModule == 9"></module-9>
<module-10 ng-if="c.firstModule == 10"></module-10>
</div>
<div class="col-xs-4"> <!-- third widget area -->
<module-1 ng-if="c.secondModule == 1"></module-1>
<module-2 ng-if="c.secondModule == 2"></module-2>
<module-3 ng-if="c.secondModule == 3"></module-3>
<module-4 ng-if="c.secondModule == 4"></module-4>
<module-5 ng-if="c.secondModule == 5"></module-5>
<module-6 ng-if="c.secondModule == 6"></module-6>
<module-7 ng-if="c.secondModule == 7"></module-7>
<module-8 ng-if="c.secondModule == 8"></module-8>
<module-9 ng-if="c.secondModule == 9"></module-9>
<module-10 ng-if="c.secondModule == 10"></module-10>
</div>
<div class="col-xs-4"> <!-- third widget area -->
<module-1 ng-if="c.thirdModule == 1"></module-1>
<module-2 ng-if="c.thirdModule == 2"></module-2>
<module-3 ng-if="c.thirdModule == 3"></module-3>
<module-4 ng-if="c.thirdModule == 4"></module-4>
<module-5 ng-if="c.thirdModule == 5"></module-5>
<module-6 ng-if="c.thirdModule == 6"></module-6>
<module-7 ng-if="c.thirdModule == 7"></module-7>
<module-8 ng-if="c.thirdModule == 8"></module-8>
<module-9 ng-if="c.thirdModule == 9"></module-9>
<module-10 ng-if="c.thirdModule == 10"></module-10>
</div>
</div>
</div>
这行得通,但我觉得这是错误的做法。如果我有 200 个小部件怎么办?我将不得不写 <module-N ng-if="c.firstModule == N"></module-N>
200 次(x3 小部件区域),这显然不是解决问题的好方法。
我也想过使用ng-include
,但据我所知它只适用于包含模板,我也需要相应的控制器来加载。
这是一个 plunker,展示了我正在努力实现的工作示例:https://plnkr.co/edit/uO8SUcmNMOGHcPjc1lWs?p=preview
如您所见,当您更改组合的值时,相应的模块将被替换。
问题是:有没有办法根据 AngularJS 1.6 中的某些控制器字段激活特定组件,而无需声明所有组件并使用 ng-if
?
这里a plunker showing a solution。
关键是创建一个动态关联模板和控制器的指令
app.directive("module", ['$compile', '$http', '$controller', '$templateCache', function ($compile, $http, $controller, $templateCache) {
return {
restrict: 'E',
replace: true,
scope: {
model: '='
},
link: function (scope, element, attrs) {
scope.$watch("model", function (newValue, oldValue, scope) {
if (newValue) {
var template = scope.model.id + ".html";
$http.get(template, { cache: $templateCache }).then(function (result) {
element.html(result.data);
element.children().data('$ngControllerController', $controller(scope.model.id + "Ctrl", { $scope: scope }));
$compile(element.contents())(scope);
});
}
});
}
};
}]);
正如我在评论部分建议的那样,您可以使用 module-slot
指令并将模块作为一种模型输入,并在内部解决所需模块的加载和编译。
此解决方案使用 ocLazyLoad,但您可以根据需要使用其他加载器。
I've made a fork of your plunkr with a solution using ocLazyLoading
因此,与其声明所有模块并使用 ng-if
控制其可见性,不如只使用一个指令,如下所示:
<div class="row">
<div class="col-xs-4">
<module-slot module="c.firstModule"></module-slot>
</div>
<div class="col-xs-4">
<module-slot module="c.secondModule"></module-slot>
</div>
<div class="col-xs-4">
<module-slot module="c.thirdModule"></module-slot>
</div>
</div>
指令:
angular.module("app")
.directive('moduleSlot', function($ocLazyLoad, $compile) {
return {
restrict: 'E',
scope: {
module: '='
},
link: function(scope, element, attrs) {
// watch the module change
scope.$watch('module', function() {
// load the module
$ocLazyLoad.load("module" + scope.module + ".js").then(function() {
// compiles the new component inside the slot
element.html("<module-" + scope.module + "></module-" + scope.module + ">");
$compile(element.contents())(scope);
}, function(e) {
console.log('errr');
console.error(e);
})
});
}
}
});
Refs
我有一个 AngularJS 1.6 应用程序,它有一个小部件部分。
小部件部分一行包含 3 个最终用户可以自行配置的小部件。他得到了所有可用小部件的列表,他可以选择要放置的小部件和位置。
每个小部件都是一个像这样初始化的组件:
(
function(angular) {
function Module1Controller() {
var vm = this;
// other stuff here
}
angular.module("app")
.component(
"module1", {
controller: Module1Controller,
templateUrl: 'module1.html'
}
);
}
)(angular)
现在,由于用户可以 select 在特定位置呈现哪个小部件,因此该数据来自网络服务。
根据从 WS 收到的数据,我需要能够 "activate" 一个组件和 "deactivate" 所有其他组件。
我的第一个想法是做这样的事情:
控制器:
(
function(angular) {
function ModulesController() {
var vm = this;
vm.firstModule = 1;
vm.secondModule = 1;
vm.thirdModule = 1;
vm.availableModules = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
}
angular.module("app")
.controller(
"ModulesController",
[
ModulesController
]
);
}
)(angular)
查看:
<div class="container-fluid" ng-controller="ModulesController as c">
<div class="row">
<div class="col-xs-4"> <!-- third widget area -->
<module-1 ng-if="c.firstModule == 1"></module-1>
<module-2 ng-if="c.firstModule == 2"></module-2>
<module-3 ng-if="c.firstModule == 3"></module-3>
<module-4 ng-if="c.firstModule == 4"></module-4>
<module-5 ng-if="c.firstModule == 5"></module-5>
<module-6 ng-if="c.firstModule == 6"></module-6>
<module-7 ng-if="c.firstModule == 7"></module-7>
<module-8 ng-if="c.firstModule == 8"></module-8>
<module-9 ng-if="c.firstModule == 9"></module-9>
<module-10 ng-if="c.firstModule == 10"></module-10>
</div>
<div class="col-xs-4"> <!-- third widget area -->
<module-1 ng-if="c.secondModule == 1"></module-1>
<module-2 ng-if="c.secondModule == 2"></module-2>
<module-3 ng-if="c.secondModule == 3"></module-3>
<module-4 ng-if="c.secondModule == 4"></module-4>
<module-5 ng-if="c.secondModule == 5"></module-5>
<module-6 ng-if="c.secondModule == 6"></module-6>
<module-7 ng-if="c.secondModule == 7"></module-7>
<module-8 ng-if="c.secondModule == 8"></module-8>
<module-9 ng-if="c.secondModule == 9"></module-9>
<module-10 ng-if="c.secondModule == 10"></module-10>
</div>
<div class="col-xs-4"> <!-- third widget area -->
<module-1 ng-if="c.thirdModule == 1"></module-1>
<module-2 ng-if="c.thirdModule == 2"></module-2>
<module-3 ng-if="c.thirdModule == 3"></module-3>
<module-4 ng-if="c.thirdModule == 4"></module-4>
<module-5 ng-if="c.thirdModule == 5"></module-5>
<module-6 ng-if="c.thirdModule == 6"></module-6>
<module-7 ng-if="c.thirdModule == 7"></module-7>
<module-8 ng-if="c.thirdModule == 8"></module-8>
<module-9 ng-if="c.thirdModule == 9"></module-9>
<module-10 ng-if="c.thirdModule == 10"></module-10>
</div>
</div>
</div>
这行得通,但我觉得这是错误的做法。如果我有 200 个小部件怎么办?我将不得不写 <module-N ng-if="c.firstModule == N"></module-N>
200 次(x3 小部件区域),这显然不是解决问题的好方法。
我也想过使用ng-include
,但据我所知它只适用于包含模板,我也需要相应的控制器来加载。
这是一个 plunker,展示了我正在努力实现的工作示例:https://plnkr.co/edit/uO8SUcmNMOGHcPjc1lWs?p=preview
如您所见,当您更改组合的值时,相应的模块将被替换。
问题是:有没有办法根据 AngularJS 1.6 中的某些控制器字段激活特定组件,而无需声明所有组件并使用 ng-if
?
这里a plunker showing a solution。 关键是创建一个动态关联模板和控制器的指令
app.directive("module", ['$compile', '$http', '$controller', '$templateCache', function ($compile, $http, $controller, $templateCache) {
return {
restrict: 'E',
replace: true,
scope: {
model: '='
},
link: function (scope, element, attrs) {
scope.$watch("model", function (newValue, oldValue, scope) {
if (newValue) {
var template = scope.model.id + ".html";
$http.get(template, { cache: $templateCache }).then(function (result) {
element.html(result.data);
element.children().data('$ngControllerController', $controller(scope.model.id + "Ctrl", { $scope: scope }));
$compile(element.contents())(scope);
});
}
});
}
};
}]);
正如我在评论部分建议的那样,您可以使用 module-slot
指令并将模块作为一种模型输入,并在内部解决所需模块的加载和编译。
此解决方案使用 ocLazyLoad,但您可以根据需要使用其他加载器。
I've made a fork of your plunkr with a solution using ocLazyLoading
因此,与其声明所有模块并使用 ng-if
控制其可见性,不如只使用一个指令,如下所示:
<div class="row">
<div class="col-xs-4">
<module-slot module="c.firstModule"></module-slot>
</div>
<div class="col-xs-4">
<module-slot module="c.secondModule"></module-slot>
</div>
<div class="col-xs-4">
<module-slot module="c.thirdModule"></module-slot>
</div>
</div>
指令:
angular.module("app")
.directive('moduleSlot', function($ocLazyLoad, $compile) {
return {
restrict: 'E',
scope: {
module: '='
},
link: function(scope, element, attrs) {
// watch the module change
scope.$watch('module', function() {
// load the module
$ocLazyLoad.load("module" + scope.module + ".js").then(function() {
// compiles the new component inside the slot
element.html("<module-" + scope.module + "></module-" + scope.module + ">");
$compile(element.contents())(scope);
}, function(e) {
console.log('errr');
console.error(e);
})
});
}
}
});
Refs