2014-09-20 23 views
0

我有几分这里复杂的需求(一个真正的头饼刷)...和我不知道的最佳方式进行:AngularJS:如何从任意类型获取属性?

要求:

建立管理页面小部件(CMS内容块)MVC5使用AngularJS作为前端(根据管理UI的其余部分)。问题是每个小部件都有自己特定的一组属性。他们都有着像TitleIsEnabled等一些特性。但一个HTML控件,例如将有一个的BodyContent场和一个滑块控件将有图像等的集合..

我首先想到的是用[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后来..这里发生的事情:

我有一个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控件为我的新特性有..下面的代码片段是HTML将其注入到上述div

<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> 

当我点击,“测试”按钮,没有任何反应...

我试图通过这个链接中列出的方法动态加载控制器:http://www.bennadel.com/blog/2553-loading-angularjs-components-after-your-application-has-been-bootstrapped.htm

它不工作。说实话,我是AngularJS的新手,并没有真正了解所有的缺陷。任何帮助都会很棒。

+0

大量的编辑...你可能会得到更好的答案分裂在两个问题。 – 2014-09-20 15:57:43

+0

该html仍包含服务器端标记。这是行不通的。 – Chandermani 2014-09-21 03:30:52

回答

0

我最终变成了KnockoutJS,部分原因是AngularJS最终对我的需求有点矫枉过正,但也因为它不能很好地处理这种情况(或者至少没有明显的和干净的方式来做到这一点)。我KnockoutJS的解决方案是下面:在我的剧本

<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> 

然后:

在主网页,我想补充一个HTML元素:

<fieldset id="widget-details"></fieldset>

被注入任意HTML的例子对于主页,我使用以下内容:

$.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"); 
}); 

a第二,当我保存,我把这个代码:

// ensure the function exists before calling it... 
if (typeof onBeforeSave == 'function') { 
    onBeforeSave(); 
} 

的作品真的很好。

0

如果您只是想获取属性及其值,那么在AngularJS或Javascript端,您可以遍历对象属性以获取定义在该对象上的所有属性。

for(var key in obj){ 
     $scope[key]=obj[key]; 
} 

一旦在范围内,您可以使用ng-model将其绑定到视图。 这种方法会为你提供数据,但是有关数据的元数据(如控制渲染用于属性需求)将无法工作。

对于高级场景,您应该尝试发送有助于在视图上呈现它的每个属性的元数据。

如果ng-model设置正确,所有数据都会发送到服务器。

在服务器上,您可以使用动态关键字作为webapi方法的输入参数,并且应该有类似的方法来使用键值对遍历有效负载。

+0

感谢您的回复,但我发现我认为这是一个更干净的方式来做到这一点。但是,我仍然有问题。请参阅我上面的编辑。 – Matt 2014-09-20 06:08:25

相关问题