我在这里有一些复杂的要求(一个真正令人头疼的问题)......而且我不确定最佳方式:
要求:
使用MVC5
为前端构建一个用于管理AngularJS
中的小部件(CMS内容块)的页面(根据管理UI的其余部分)。问题是每个小部件都有自己特定的属性集。它们都共享一些属性,如Title
,IsEnabled
等。但是一个HTML Widget例如将有一个BodyContent字段,一个Slider Widget将有一个图像集合等。
我的第一个想法是使用[UIHint]
和Html.EditorFor
,以便每个窗口小部件类型都有自己的标记..我认为这非常简单,但我们怎样才能从任何部分获取属性这样的任意小部件进入AngularJS
模型?
示例控制器
widgetsApp.controller('widgetController', function ($scope, $http) {
$scope.emptyGuid = '00000000-0000-0000-0000-000000000000';
$scope.id = $scope.emptyGuid;
$scope.title = '';
$scope.order = 0;
$scope.enabled = false;
$scope.widgetType = '';
$scope.zoneId = $scope.emptyGuid;
// etc
// how to get properties of ANY widget type?
这甚至可能吗?有更好的解决方案吗?注意,如果代码可以支持我的要求,我可能会考虑更改代码以使用Knockout
或其他一些此类框架。
修改
请注意,问题进一步复杂化,因为需要将这样的模型传递回服务器并在那里处理它。在常规MVC控制器中,我可以使用Request.Form
来检查其他值是什么,但我使用Web API
并且不确定那里是否有可能。
修改2
好的,所以我觉得我走在正确的轨道上,但仍然有问题。首先,这是我的进步:
我发现了.factory
,并制作了这样的测试页:
<div ng-app="myApp">
<div ng-controller="controller1">
<button class="btn btn-primary" ng-click="showAllInfo()">Show Info</button>
</div>
<div ng-controller="controller2">
</div>
</div>
<script type="text/javascript">
var myApp = angular.module('myApp', []);
myApp.factory('widgetModel', function () {
return {
id: '00000000-0000-0000-0000-000000000000',
title: '',
order: 0,
enabled: false,
widgetName: '',
widgetType: '',
zoneId: '00000000-0000-0000-0000-000000000000',
displayCondition: '',
widgetValues: '',
pageId: null,
cultureCode: '',
refId: null,
};
});
// This is representative of the main controller
myApp.controller('controller1', function ($scope, widgetModel) {
$scope.emptyGuid = '00000000-0000-0000-0000-000000000000';
$scope.model = widgetModel;
$scope.model.id = $scope.emptyGuid;
$scope.showAllInfo = function () {
alert("id: " + $scope.model.id + ", New Property: " + $scope.model.myNewProperty);
};
});
// This is representative of the details controller (to add properties specific to that particular widget type)
myApp.controller('controller2', function ($scope, widgetModel) {
$scope.model = widgetModel;
$scope.model.myNewProperty = "My Awesome Widget";
});
</script>
上面的测试效果很好..但是,当我在我的实际应用程序中使用这种代码时,它无法工作,我相信的原因是因为第二个控制器稍后会被注入到DOM中。这里&#39;发生了什么:
我有一个div
如下
<div ng-bind-html="widgetDetails"></div>
并在加载其他详细信息后,我为此加载了html:
$http.get("/admin/widgets/get-editor-ui/" + $scope.model.id).success(function (json) {
$scope.widgetDetails = $sce.trustAsHtml(json.Content);
});
有效..我可以在那里看到我的新属性的html控件..以下片段是注入上面div
的HTML:
<div ng-controller="widgetDetailsController">
<div class="col-sm-12 col-md-12">
<div class="form-group">
@Html.Label("BodyContent", "Body Content", new { @class = "control-label" })
@Html.TextArea("BodyContent", null, new { @class = "form-control", ng_model = "model.bodyContent", ui_tinymce = "tinyMCEOptions_BodyContent" })
</div>
</div>
<button class="btn" ng-click="test()">Test</button>
</div>
<script type="text/javascript">
widgetsApp.controller('widgetDetailsController', function ($scope, $http, widgetModel) {
$scope.model = widgetModel;
$scope.json = angular.fromJson($scope.model.widgetValues);
$scope.model.bodyContent = $scope.json.bodyContent || "";
$scope.test = function () {
alert($scope.model.bodyContent);
};
});
</script>
当我点击时,&#34;测试&#34;按钮,没有任何反应......
我尝试通过此链接中列出的方法动态加载控制器:http://www.bennadel.com/blog/2553-loading-angularjs-components-after-your-application-has-been-bootstrapped.htm
它不起作用。说实话,我是AngularJS的新手,并不是真的知道它的所有内容......任何帮助都会很棒。
答案 0 :(得分:0)
如果您只是想获取属性及其值,那么在AngularJS或Javascript端,您可以迭代对象属性以获取在对象上定义的所有属性。
for(var key in obj){
$scope[key]=obj[key];
}
在范围内,您可以使用ng-model
将其绑定到视图。
这种方法可以为您提供数据,但有关数据的元数据(如用于呈现属性需求的控件)将无效。
对于高级场景,您应该尝试发送有助于在视图上呈现它的每个属性的元数据。
如果正确设置了ng-model,所有数据都将发送到服务器。
在服务器上,您可以使用dynamic关键字作为webapi方法的输入参数,并且应该有一个类似的方法来使用键值对迭代有效负载。
答案 1 :(得分:0)
我最终改为KnockoutJS,部分是因为AngularJS最终对我的需求有点过分,但也因为它无法很好地处理这种情况(或者至少没有明显和干净的方法来做它)。我的KnockoutJS解决方案如下:
在主页面中,我添加了一个html元素:
<fieldset id="widget-details"></fieldset>
要注入的任意HTML的示例:
<div id="widget-content" class="col-sm-12 col-md-12">
<div class="form-group">
@Html.Label("BodyContent", "Body Content", new { @class = "control-label" })
@Html.TextArea("BodyContent", null, new { @class = "form-control", data_bind = "wysiwyg: bodyContent, wysiwygConfig: tinyMCEConfig" })
</div>
</div>
<script type="text/javascript">
function updateModel() {
var data = ko.mapping.fromJSON(viewModel.widgetValues());
viewModel.bodyContent = ko.observable("");
if (data && data.BodyContent) {
viewModel.bodyContent(data.BodyContent());
}
viewModel.tinyMCEConfig = {
theme: "modern",
plugins: [
"advlist autolink lists link image charmap print preview hr anchor pagebreak",
"searchreplace wordcount visualblocks visualchars code fullscreen",
"insertdatetime media nonbreaking save table contextmenu directionality",
"emoticons template paste textcolor"
],
toolbar1: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image",
toolbar2: "print preview media | forecolor backcolor emoticons",
image_advtab: true,
templates: [
{ title: 'Test template 1', content: 'Test 1' },
{ title: 'Test template 2', content: 'Test 2' }
],
content_css: tinyMCEContentCss
};
};
function onBeforeSave() {
var data = {
BodyContent: viewModel.bodyContent()
};
viewModel.widgetValues(ko.mapping.toJSON(data));
};
</script>
然后在我的主页脚本中,我使用以下内容:
$.ajax({
url: "/admin/widgets/get-editor-ui/" + self.id(),
type: "GET",
dataType: "json",
async: false
})
.done(function (json) {
var result = $(json.Content);
var content = $(result.filter('#widget-content')[0]);
var details = $('<div>').append(content.clone()).html();
$("#widget-details").html(details);
var scripts = result.filter('script');
scripts.appendTo('body');
// ensure the function exists before calling it...
if (typeof updateModel == 'function') {
updateModel();
var elementToBind = $("#widget-details")[0];
ko.cleanNode(elementToBind);
ko.applyBindings(viewModel, elementToBind);
}
})
.fail(function () {
$.notify("There was an error when retrieving the record.", "error");
});
当我保存时,我会调用此代码:
// ensure the function exists before calling it...
if (typeof onBeforeSave == 'function') {
onBeforeSave();
}
工作得很好。