Asp.net mvc AngularJS:如何从任意类型获取属性?

Asp.net mvc AngularJS:如何从任意类型获取属性?,asp.net-mvc,angularjs,asp.net-web-api,asp.net-mvc-5,Asp.net Mvc,Angularjs,Asp.net Web Api,Asp.net Mvc 5,我这里有一个复杂的要求,一个真正令人头痛的人。。。我不确定最好的方法是什么: 要求: 根据管理UI的其余部分,在前端使用AngularJS构建一个页面,用于管理MVC5中的widgets CMS内容块。问题是每个小部件都有自己的一组特定属性。它们都有一些共同的属性,如标题、可访问性等。。但是一个HTML小部件将有一个BodyContent字段,一个Slider小部件将有一个图像集合,等等 我的第一个想法是使用[UIHint]和Html.EditorFor,这样每个小部件类型都有自己的标记。。我认

我这里有一个复杂的要求,一个真正令人头痛的人。。。我不确定最好的方法是什么:

要求:

根据管理UI的其余部分,在前端使用AngularJS构建一个页面,用于管理MVC5中的widgets CMS内容块。问题是每个小部件都有自己的一组特定属性。它们都有一些共同的属性,如标题、可访问性等。。但是一个HTML小部件将有一个BodyContent字段,一个Slider小部件将有一个图像集合,等等

我的第一个想法是使用[UIHint]和Html.EditorFor,这样每个小部件类型都有自己的标记。。我认为这很简单,但是我们如何将任意小部件的属性输入AngularJS模型呢

示例控制器

这可能吗?有更好的解决办法吗?注意,如果可以支持我的需求,我可以考虑更改代码以使用KokOutt或其他这样的框架。 编辑

请注意,这个问题更加复杂,因为需要将这样的模型传递回服务器并在那里进行处理。在常规MVC控制器中,我可以使用Request.Form来检查还有哪些其他值,但我使用的是WebAPI,不确定是否有可能

编辑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>
行得通。。我可以在那里看到我的新属性的html控件。。以下代码段是注入上述div的HTML:

当我点击测试按钮时,什么也没发生

我尝试通过此链接中概述的方法动态加载控制器:


它不起作用。不过老实说,我对AngularJS是个新手,并不真正了解它的所有细节。。任何帮助都会很好。

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

for(var key in obj){
      $scope[key]=obj[key];
 }
一旦进入范围,您就可以使用ng模型将其绑定到视图。 这种方法可以获得数据,但有关数据的元数据(如要为属性需求呈现的控件)不起作用

对于高级方案,您应该尝试发送有关每个属性的元数据,以帮助在视图上呈现这些属性

如果ng模型设置正确,所有数据都将发送到服务器


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

我最终改为KnockoutJS,部分原因是AngularJS对我的需求来说有点过分,但也因为它不能很好地处理这种情况,或者至少没有明显和干净的方法来处理。我的KnockoutJS解决方案如下:

在主页面中,我添加了一个html元素:

要注入的任意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>

非常有效。

谢谢你的回复,但我发现我认为这是一种更干净的方法。然而,我仍然有问题。请看我上面的编辑。很多编辑。。。分为两个问题,您可能会得到更好的答案。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>
for(var key in obj){
      $scope[key]=obj[key];
 }
<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();
}