如何使用knockout.js与ASP.NET MVC的ViewModels?如何使用knockou

2019-06-01 03:51发布

赏金

它已经一段时间,我仍然有一对夫妇的悬而未决的问题。 我希望通过加入悬赏也许这些问题将得到回答。

  1. 如何使用与knockout.js HTML辅助
  2. 为什么需要文档准备,使其工作(更多信息请参见第一次编辑)

  3. 我怎么做这样的事,如果我使用我的观点车型淘汰赛映射? 由于我没有因映射功能。

     function AppViewModel() { // ... leave firstName, lastName, and fullName unchanged here ... this.capitalizeLastName = function() { var currentVal = this.lastName(); // Read the current value this.lastName(currentVal.toUpperCase()); // Write back a modified value }; 
  4. 我想,就好像用户取消请求,我希望能够回到过去的值用比如我希望能够回滚观测插件。 从我的研究,这似乎被人喜欢制作插件来实现editables

    如何,如果我使用映射我使用类似的东西? 我真的不想去,我有我的观点手动映射是我每个MVC VIEWMODE字段映射到一个KO模型字段,因为我想少内嵌JavaScript作为可能的,只是好像双重的工作,这是一个方法为什么我喜欢的映射。

  5. 我很担心,使这项工作容易(通过映射)我会失去很多KO电源,但在另一方面,我很担心,手动映射将只是一个大量的工作,会让我的看法包含了太多的信息和有可能成为在未来难以维持(说,如果我在MVC模式删除属性我也必须将它在KO视图模型)


原贴

我使用asp.net的MVC 3,我寻找到淘汰赛,因为它看起来很酷,但我有一个很难弄清楚它是如何工作与asp.net的MVC特别是查看模型。

对我来说,现在我做这样的事情

 public class CourseVM
    {
        public int CourseId { get; set; }
        [Required(ErrorMessage = "Course name is required")]
        [StringLength(40, ErrorMessage = "Course name cannot be this long.")]
        public string CourseName{ get; set; }


        public List<StudentVm> StudentViewModels { get; set; }

}

我想有一个虚拟机有类似CourseName一些基本特性,它会在它上面的一些简单的验证。 如果需要虚拟测量模型可能包含其他视图模型中它。

然后我就通过这个虚拟机视图中,我会用HTML助手来帮我把它显示给用户。

@Html.TextBoxFor(x => x.CourseName)

我可能有一些foreach循环或东西来获取数据了学生视图模型的集合。

然后,当我将提交表单,我会用jQuery和serialize array ,并将其发送到将其绑定回视图模型控制器的操作方法。

随着knockout.js它是所有不同的,因为你现在得到的ViewModels它和所有的例子我看到他们不使用HTML辅助。

你如何使用MVC的这些特点2与knockout.js?

我发现这个视频 ,并简要地(视频@ 18:48的最后几分钟)进入的方式基本上由具有有knockout.js视图模型是获取视图模型分配值的内嵌脚本使用的ViewModels。

这是做它的唯一途径? 如何在我的用具有它的ViewModels的集合的例子吗? 我必须有一个foreach循环或东西来提取所有的值并把它分配到淘汰赛?

至于HTML辅助视频说他们一无所知。

这些都是2个区是混淆了赫克了我本就不多的人似乎谈论它,它让我感到困惑的初始值,一切是如何得到的视图当过例子只是一些硬编码值例子的。


编辑

我想什么了Darin季米特洛夫曾建议,这似乎工作(我不得不作出一些改变他的代码虽然)。 不知道为什么,我不得不使用文件准备好,但不知何故一切都还没有准备好,没有它。

@model MvcApplication1.Models.Test

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <title>Index</title>
    <script src="../../Scripts/jquery-1.5.1.js" type="text/javascript"></script>
    <script src="../../Scripts/knockout-2.1.0.js" type="text/javascript"></script>
    <script src="../../Scripts/knockout.mapping-latest.js" type="text/javascript"></script>
   <script type="text/javascript">

   $(function()
   {
      var model = @Html.Raw(Json.Encode(Model));


// Activates knockout.js
ko.applyBindings(model);
   });

</script>

</head>
<body>
    <div>
        <p>First name: <strong data-bind="text: FirstName"></strong></p>
        <p>Last name: <strong data-bind="text: LastName"></strong></p>
        @Model.FirstName , @Model.LastName
    </div>
</body>
</html>

我不得不将其套在一个jQuery文档准备,使其工作。

我也得到这样的警告。 不知道这是怎么一回事。

Warning 1   Conditional compilation is turned off   -> @Html.Raw

所以我有一个起点,我想至少在我做多一些玩耍以及如何工作将更新。

我试图去通过互动教程,但使用一个视图模型来代替。

不知道如何解决这些部件还

function AppViewModel() {
    this.firstName = ko.observable("Bert");
    this.lastName = ko.observable("Bertington");
}

要么

function AppViewModel() {
    // ... leave firstName, lastName, and fullName unchanged here ...

    this.capitalizeLastName = function() {
        var currentVal = this.lastName();        // Read the current value
        this.lastName(currentVal.toUpperCase()); // Write back a modified value
    };


编辑2

我已经能够找出第一个问题。 没有关于第二个问题的线索。 然而,尽管。 任何人有什么想法?

 @model MvcApplication1.Models.Test

    @{
        Layout = null;
    }

    <!DOCTYPE html>

    <html>
    <head>
        <title>Index</title>
        <script src="../../Scripts/jquery-1.5.1.js" type="text/javascript"></script>
        <script src="../../Scripts/knockout-2.1.0.js" type="text/javascript"></script>
        <script src="../../Scripts/knockout.mapping-latest.js" type="text/javascript"></script>
       <script type="text/javascript">

       $(function()
       {
        var model = @Html.Raw(Json.Encode(Model));
        var viewModel = ko.mapping.fromJS(model);
        ko.applyBindings(viewModel);

       });

    </script>

    </head>
    <body>
        <div>
            @*grab values from the view model directly*@
            <p>First name: <strong data-bind="text: FirstName"></strong></p>
            <p>Last name: <strong data-bind="text: LastName"></strong></p>

            @*grab values from my second view model that I made*@
            <p>SomeOtherValue <strong data-bind="text: Test2.SomeOtherValue"></strong></p>
            <p>Another <strong data-bind="text: Test2.Another"></strong></p>

            @*allow changes to all the values that should be then sync the above values.*@
            <p>First name: <input data-bind="value: FirstName" /></p>
            <p>Last name: <input data-bind="value: LastName" /></p>
            <p>SomeOtherValue <input data-bind="value: Test2.SomeOtherValue" /></p>
            <p>Another <input data-bind="value: Test2.Another" /></p>

           @* seeing if I can do it with p tags and see if they all update.*@
            <p data-bind="foreach: Test3">
                <strong data-bind="text: Test3Value"></strong> 
            </p>

     @*took my 3rd view model that is in a collection and output all values as a textbox*@       
    <table>
        <thead><tr>
            <th>Test3</th>
        </tr></thead>
          <tbody data-bind="foreach: Test3">
            <tr>
                <td>    
                    <strong data-bind="text: Test3Value"></strong> 
<input type="text" data-bind="value: Test3Value"/>
                </td>
            </tr>    
        </tbody>
    </table>

调节器

  public ActionResult Index()
    {
              Test2 test2 = new Test2
        {
            Another = "test",
            SomeOtherValue = "test2"
        };

        Test vm = new Test
        {
            FirstName = "Bob",
            LastName = "N/A",
             Test2 = test2,

        };
        for (int i = 0; i < 10; i++)
        {
            Test3 test3 = new Test3
            {
                Test3Value = i.ToString()
            };

             vm.Test3.Add(test3);
        }

        return View(vm);
    }

Answer 1:

我想我已经总结了所有的问题,如果我错过了什么,请告诉我( 如果你能在一个地方你所有的问题归纳起来将是很好 =))

注意。 与兼容性ko.editable增加的插件

下载完整的代码

如何使用与knockout.js HTML辅助

这很简单:

@Html.TextBoxFor(model => model.CourseId, new { data_bind = "value: CourseId" })

哪里:

  • value: CourseId表明您绑定的value的财产input与控制CourseId从你的模型属性和脚本模型

其结果是:

<input data-bind="value: CourseId" data-val="true" data-val-number="The field CourseId must be a number." data-val-required="The CourseId field is required." id="CourseId" name="CourseId" type="text" value="12" />

为什么需要文档准备,使其工作(更多信息请参见第一次编辑)

为什么你需要使用我不明白,还没有ready事件序列化模式,但它似乎仅仅是必需的 (不必担心它虽然)

我怎么做这样的事,如果我使用我的观点车型淘汰赛映射? 由于我没有因映射功能。

如果我理解正确的话,你需要一种新的方法追加到KO模型,很好,很容易合并模型

欲了解更多信息,在部分来自不同的来源- -Mapping

function viewModel() {
    this.addStudent = function () {
        alert("de");
    };
};

$(function () {
    var jsonModel = '@Html.Raw(JsonConvert.SerializeObject(this.Model))';
    var mvcModel = ko.mapping.fromJSON(jsonModel);

    var myViewModel = new viewModel();
    var g = ko.mapping.fromJS(myViewModel, mvcModel);

    ko.applyBindings(g);
});

关于警告你receiveing

警告1个条件编译被关闭 - > @ Html.Raw

你需要使用引号

与ko.editable插件兼容性

我认为这将是更为复杂,但事实证明,整合是很容易的,为了使你的模型编辑只需添加以下行:(记住,在这种情况下,我使用的是混合模式,从服务器在客户端加入扩展性和可编辑的简单的工作......这是伟大的):

    ko.editable(g);
    ko.applyBindings(g);

在这里,您只需要使用由插件添加的扩展您的绑定 ,比如我有一个按钮,开始编辑我的领域,如这和这个按钮我开始编辑过程:

    this.editMode = function () {
        this.isInEditMode(!this.isInEditMode());
        this.beginEdit();
    };

然后,我已经提交并取消用下面的代码按钮:

    this.executeCommit = function () {
        this.commit();
        this.isInEditMode(false);
    };
    this.executeRollback = function () {
        if (this.hasChanges()) {
            if (confirm("Are you sure you want to discard the changes?")) {
                this.rollback();
                this.isInEditMode(false);
            }
        }
        else {
            this.rollback();
            this.isInEditMode(false);
        }
    };

最后,我有一个字段,以指示场是否在编辑模式与否,这只是使能属性绑定。

this.isInEditMode = ko.observable(false);

关于您的问题阵

我可能有一些foreach循环或东西来获取数据了学生视图模型的集合。

然后,当我将提交表单,我会用jQuery和序列化阵列,并将其发送到将其绑定回视图模型控制器的操作方法。

你可以做同样的KO,在下面的例子中,我将创建以下的输出:

基本上在这里,你有两个列表,使用创建的Helpers ,并与KO绑定,他们有一个dblClick事件绑定是发射时,从当前列表中删除选定的项目,并把它添加到其他列表中,当你邮寄到Controller中,每个列表的内容被作为JSON数据和重新连接到服务器模型

掘金:

  • Newtonsoft
  • jQuery的
  • knockoutjs
  • Knockout.Mapping

外部脚本 。

控制器代码

    [HttpGet]
    public ActionResult Index()
    {
        var m = new CourseVM { CourseId = 12, CourseName = ".Net" };

        m.StudentViewModels.Add(new StudentVm { ID = 545, Name = "Name from server", Lastname = "last name from server" });

        return View(m);
    }

    [HttpPost]
    public ActionResult Index(CourseVM model)
    {
        if (!string.IsNullOrWhiteSpace(model.StudentsSerialized))
        {
            model.StudentViewModels = JsonConvert.DeserializeObject<List<StudentVm>>(model.StudentsSerialized);
            model.StudentsSerialized = string.Empty;
        }

        if (!string.IsNullOrWhiteSpace(model.SelectedStudentsSerialized))
        {
            model.SelectedStudents = JsonConvert.DeserializeObject<List<StudentVm>>(model.SelectedStudentsSerialized);
            model.SelectedStudentsSerialized = string.Empty;
        }

        return View(model);
    }

模型

public class CourseVM
{
    public CourseVM()
    {
        this.StudentViewModels = new List<StudentVm>();
        this.SelectedStudents = new List<StudentVm>();
    }

    public int CourseId { get; set; }

    [Required(ErrorMessage = "Course name is required")]
    [StringLength(100, ErrorMessage = "Course name cannot be this long.")]
    public string CourseName { get; set; }

    public List<StudentVm> StudentViewModels { get; set; }
    public List<StudentVm> SelectedStudents { get; set; }

    public string StudentsSerialized { get; set; }
    public string SelectedStudentsSerialized { get; set; }
}

public class StudentVm
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Lastname { get; set; }
}

CSHTML页

@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>CourseVM</legend>

        <div>
            <div class="editor-label">
                @Html.LabelFor(model => model.CourseId)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.CourseId, new { data_bind = "enable: isInEditMode, value: CourseId" })
                @Html.ValidationMessageFor(model => model.CourseId)
            </div>

            <div class="editor-label">
                @Html.LabelFor(model => model.CourseName)
            </div>
            <div class="editor-field">
                @Html.TextBoxFor(model => model.CourseName, new { data_bind = "enable: isInEditMode, value: CourseName" })
                @Html.ValidationMessageFor(model => model.CourseName)
            </div>
            <div class="editor-label">
                @Html.LabelFor(model => model.StudentViewModels);
            </div>
            <div class="editor-field">

                @Html.ListBoxFor(
                    model => model.StudentViewModels,
                    new SelectList(this.Model.StudentViewModels, "ID", "Name"),
                    new
                    {
                        style = "width: 37%;",
                        data_bind = "enable: isInEditMode, options: StudentViewModels, optionsText: 'Name', value: leftStudentSelected, event: { dblclick: moveFromLeftToRight }"
                    }
                )
                @Html.ListBoxFor(
                    model => model.SelectedStudents,
                    new SelectList(this.Model.SelectedStudents, "ID", "Name"),
                    new
                    {
                        style = "width: 37%;",
                        data_bind = "enable: isInEditMode, options: SelectedStudents, optionsText: 'Name', value: rightStudentSelected, event: { dblclick: moveFromRightToLeft }"
                    }
                )
            </div>

            @Html.HiddenFor(model => model.CourseId, new { data_bind="value: CourseId" })
            @Html.HiddenFor(model => model.CourseName, new { data_bind="value: CourseName" })
            @Html.HiddenFor(model => model.StudentsSerialized, new { data_bind = "value: StudentsSerialized" })
            @Html.HiddenFor(model => model.SelectedStudentsSerialized, new { data_bind = "value: SelectedStudentsSerialized" })
        </div>

        <p>
            <input type="submit" value="Save" data-bind="enable: !isInEditMode()" /> 
            <button data-bind="enable: !isInEditMode(), click: editMode">Edit mode</button><br />
            <div>
                <button data-bind="enable: isInEditMode, click: addStudent">Add Student</button>
                <button data-bind="enable: hasChanges, click: executeCommit">Commit</button>
                <button data-bind="enable: isInEditMode, click: executeRollback">Cancel</button>
            </div>
        </p>
    </fieldset>
}

脚本

<script src="@Url.Content("~/Scripts/jquery-1.7.2.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/knockout-2.1.0.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/knockout.mapping-latest.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/ko.editables.js")" type="text/javascript"></script>

<script type="text/javascript">
    var g = null;
    function ViewModel() {
        this.addStudent = function () {
            this.StudentViewModels.push(new Student(25, "my name" + new Date(), "my last name"));
            this.serializeLists();
        };
        this.serializeLists = function () {
            this.StudentsSerialized(ko.toJSON(this.StudentViewModels));
            this.SelectedStudentsSerialized(ko.toJSON(this.SelectedStudents));
        };
        this.leftStudentSelected = ko.observable();
        this.rightStudentSelected = ko.observable();
        this.moveFromLeftToRight = function () {
            this.SelectedStudents.push(this.leftStudentSelected());
            this.StudentViewModels.remove(this.leftStudentSelected());
            this.serializeLists();
        };
        this.moveFromRightToLeft = function () {
            this.StudentViewModels.push(this.rightStudentSelected());
            this.SelectedStudents.remove(this.rightStudentSelected());
            this.serializeLists();
        };
        this.isInEditMode = ko.observable(false);
        this.executeCommit = function () {
            this.commit();
            this.isInEditMode(false);
        };
        this.executeRollback = function () {
            if (this.hasChanges()) {
                if (confirm("Are you sure you want to discard the changes?")) {
                    this.rollback();
                    this.isInEditMode(false);
                }
            }
            else {
                this.rollback();
                this.isInEditMode(false);
            }
        };
        this.editMode = function () {
            this.isInEditMode(!this.isInEditMode());
            this.beginEdit();
        };
    }

    function Student(id, name, lastName) {
        this.ID = id;
        this.Name = name;
        this.LastName = lastName;
    }

    $(function () {
        var jsonModel = '@Html.Raw(JsonConvert.SerializeObject(this.Model))';
        var mvcModel = ko.mapping.fromJSON(jsonModel);

        var myViewModel = new ViewModel();
        g = ko.mapping.fromJS(myViewModel, mvcModel);

        g.StudentsSerialized(ko.toJSON(g.StudentViewModels));
        g.SelectedStudentsSerialized(ko.toJSON(g.SelectedStudents));

        ko.editable(g);
        ko.applyBindings(g);
    });
</script>

注:我只是说这几行:

        @Html.HiddenFor(model => model.CourseId, new { data_bind="value: CourseId" })
        @Html.HiddenFor(model => model.CourseName, new { data_bind="value: CourseName" })

因为当我提交表单我字段将被禁用,所以值不传输到服务器,这就是为什么我添加了几个隐藏字段这样的伎俩



Answer 2:

你可以系列化你的ASP.NET MVC视图模型到一个JavaScript变量:

@model CourseVM
<script type="text/javascript">
    var model = @Html.Raw(Json.Encode(Model));
    // go ahead and use the model javascript variable to bind with ko
</script>

有很多的例子在淘汰赛的文档 ,你可以去。



Answer 3:

为了获得额外的计算性能后,服务器映射时,将需要进一步加强对客户端您的ViewModels。

例如:

var viewModel = ko.mapping.fromJS(model);

viewModel.capitalizedName = ko.computed(function() {...}, viewModel);

所以,每当你从生JSON映射你需要重新计算的性能。

此外,该映射插件提供了增量更新,而不是每次来回走时重建它视图模型的能力(使用一个额外的参数fromJS ):

// Every time data is received from the server:
ko.mapping.fromJS(data, viewModel);

这对你的被映射只是性能的模型执行的增量数据更新。 您可以在阅读更多有关该映射文档

您在Darin的答案的评论提到FluentJSON包。 我的那个作者,但它的使用情况比ko.mapping更具体。 我一般只使用它,如果你的ViewModels是单向的(即服务器 - >客户端),然后数据被调回一些不同的格式(或者根本没有)。 或者,如果你的JavaScript视图模型需要在您的服务器模型实质上不同的格式。



文章来源: How to use knockout.js with ASP.NET MVC ViewModels?