如何使用knockout.js在ASP.NET MVC中的ViewModels? [英] How to use knockout.js with ASP.NET MVC ViewModels?

查看:201
本文介绍了如何使用knockout.js在ASP.NET MVC中的ViewModels?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

赏金

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


  1. 如何使用带有knockout.js HTML辅助

  2. 为什么需要准备的文件,使工作(见第一次编辑获取更多信息)


  3. 我如何做这样的事情,如果我用我的观点车型淘汰赛映射?由于我没有一个函数,由于映射。

     函数AppViewModel(){    // ...留下名字,姓氏,全名和持平这里...    this.capitalizeLastName =功能(){    变种currentVal = this.lastName(); //读取当前值    this.lastName(currentVal.toUpperCase()); //写回修改的值};


  4. 我想,如果用户取消请求,我希望能够回到过去的值用比如我希望能够回滚观测插件。从我的研究,这似乎被人们制作插件,像 editables

    实现

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


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




原贴

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

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

 公共类CourseVM
    {
        公众诠释CourseId {搞定;组; }
        [必需(的ErrorMessage =课程名称是必需)]
        [StringLength(40的ErrorMessage =课程名称不可能长久的。)
        公共字符串课程名{获得;组; }
        公开名单< StudentVm> StudentViewModels {搞定;组; }}

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

然后我会通过这个虚拟机的视图是我会用HTML辅助来帮助我把它显示给用户。

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

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

后来,当我想提出我会使用jQuery和连载阵,并将其发送到将其绑定回视图模型控制器操作方法的形式。

使用knockout.js这是所有不同,因为你现在得到的ViewModels它和所有的例子我见过他们不使用HTML佣工。

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

我发现<一个href=\"http://channel9.msdn.com/posts/ASPNET-MVC-With-Community-Tools-Part-11-KnockoutJS?format=html5\">这个视频并简要(视频最后几分钟@ 18:48)进入了一种方法基本上具有有获取视图模型分配的值knockout.js视图模型内嵌脚本使用的ViewModels。

这是做到这一点的唯一途径?怎么样在我的有它的ViewModels的集合的例子吗?我必须有一个foreach循环或东西提取出来的所有值,并将其分配到淘汰赛?

对于HTML辅助视频只字未提他们。

这是混淆了赫克了我的2个区域不许多人似乎谈论它,它让我困惑的是如何初始值,一切都越来越向视图当过例子只是一些硬codeD值的例子。



修改

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

  @model MvcApplication1.Models.Test@ {
    布局= NULL;
}&LT;!DOCTYPE HTML&GT;&LT; HTML和GT;
&LT; HEAD&GT;
    &LT;标题&GT;指数&LT; /标题&GT;
    &LT;脚本SRC =../../脚本/ jQuery的-1.5.1.js类型=文/ JavaScript的&GT;&LT; / SCRIPT&GT;
    &LT;脚本SRC =../../脚本/淘汰赛2.1.0.js类型=文/ JavaScript的&GT;&LT; / SCRIPT&GT;
    &LT;脚本SRC =../../脚本/ knockout.mapping-latest.js类型=文/ JavaScript的&GT;&LT; / SCRIPT&GT;
   &LT;脚本类型=文/ JavaScript的&GT;   $(函数()
   {
      VAR模型= @ Html.Raw(Json.En code(型号));
//激活knockout.js
ko.applyBindings(模型);
   });&LT; / SCRIPT&GT;&LT; /头&GT;
&LT;身体GT;
    &LT; D​​IV&GT;
        &LT; P&gt;首先名称:其中,强大的数据绑定=TEXT:名字&GT;&LT; / STRONG&GT;&LT; / P&GT;
        &LT; P&GT;姓:&LT;强大的数据绑定=TEXT:名字&GT;&LT; / STRONG&GT;&LT; / P&GT;
        @ Model.FirstName,@ Model.LastName
    &LT; / DIV&GT;
&LT; /身体GT;
&LT; / HTML&GT;

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

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

 警告1条件编译被关闭 - &GT; @ Html.Raw

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

我试图去通过互动式教学,但使用一个ViewModel来代替。

不知道如何应对这些部分尚未

 函数AppViewModel(){
    this.firstName = ko.observable(伯特);
    this.lastName = ko.observable(Bertington);
}

 函数AppViewModel(){
    // ...留下名字,姓氏,全名和持平这里...    this.capitalizeLastName =功能(){
        变种currentVal = this.lastName(); //读取当前值
        this.lastName(currentVal.toUpperCase()); //写回修改的值
    };



修改2

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

  @model MvcApplication1.Models.Test    @ {
        布局= NULL;
    }    &LT;!DOCTYPE HTML&GT;    &LT; HTML和GT;
    &LT; HEAD&GT;
        &LT;标题&GT;指数&LT; /标题&GT;
        &LT;脚本SRC =../../脚本/ jQuery的-1.5.1.js类型=文/ JavaScript的&GT;&LT; / SCRIPT&GT;
        &LT;脚本SRC =../../脚本/淘汰赛2.1.0.js类型=文/ JavaScript的&GT;&LT; / SCRIPT&GT;
        &LT;脚本SRC =../../脚本/ knockout.mapping-latest.js类型=文/ JavaScript的&GT;&LT; / SCRIPT&GT;
       &LT;脚本类型=文/ JavaScript的&GT;       $(函数()
       {
        VAR模型= @ Html.Raw(Json.En code(型号));
        VAR视图模型= ko.mapping.fromJS(模型);
        ko.applyBindings(视图模型);       });    &LT; / SCRIPT&GT;    &LT; /头&GT;
    &LT;身体GT;
        &LT; D​​IV&GT;
            @ *从视图模型抢值直接@ *
            &LT; P&gt;首先名称:其中,强大的数据绑定=TEXT:名字&GT;&LT; / STRONG&GT;&LT; / P&GT;
            &LT; P&GT;姓:&LT;强大的数据绑定=TEXT:名字&GT;&LT; / STRONG&GT;&LT; / P&GT;            @ *从我做我的第二个视图模型抢值* @
            &LT; P&GT; SomeOtherValue&LT;强大的数据绑定=TEXT:Test2.SomeOtherValue&GT;&LT; / STRONG&GT;&LT; / P&GT;
            &LT; P&GT;另&LT;强大的数据绑定=TEXT:Test2.Another&GT;&LT; / STRONG&GT;&LT; / P&GT;            @ *允许更改,应该是然后同步上面值的所有值。* @
            &LT; P&gt;首先名称:其中,输入数据绑定=值:名字/&GT;&LT; / P&GT;
            &LT; P&GT;姓氏:其中,输入数据绑定=值:名字/&GT;&LT; / P&GT;
            &LT; P&GT; SomeOtherValue&LT;输入数据绑定=值:Test2.SomeOtherValue/&GT;&LT; / P&GT;
            &LT; P&GT;另&LT;输入数据绑定=值:Test2.Another/&GT;&LT; / P&GT;           @ *看,如果我可以,如果他们都更新p标签做看看。* @
            &LT; P数据绑定=的foreach:Test3的&GT;
                &LT;强大的数据绑定=TEXT:Test3Value&GT;&LT; / STRONG&GT;
            &所述; / P&GT;     @ *把我这是在采集和输出的所有值作为一个文本框3视图模型* @
    &LT;表&gt;
        &所述; THEAD&GT;&下; TR&GT;
            &LT;第i Test3的&LT; /第i
        &LT; / TR&GT;&LT; / THEAD&GT;
          &LT; TBODY数据绑定=的foreach:Test3的&GT;
            &所述; TR&GT;
                &所述; TD&GT;
                    &LT;强大的数据绑定=TEXT:Test3Value&GT;&LT; / STRONG&GT;
&LT;输入类型=文本数据绑定=值:Test3Value/&GT;
                &LT; / TD&GT;
            &LT; / TR&GT;
        &LT; / TBODY&GT;
    &LT; /表&gt;

控制器

 公众的ActionResult指数()
    {
              Test2的测试2 =新的Test2
        {
            另一个=测试,
            SomeOtherValue =TEST2
        };        测试VM =新测试
        {
            名字=鲍勃,
            姓氏=N / A,
             测试2 = TEST2,        };
        的for(int i = 0;我小于10;我++)
        {
            TEST3 TEST3 =新TEST3
            {
                Test3Value = i.ToString()
            };             vm.Test3.Add(TEST3);
        }        返回查看(VM);
    }


解决方案

我想我已经总结了所有的问题,如果我错过了什么,请让我知道(的如果你能概括起来在一个地方你所有的问题会是很好的=))

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

下载满code

如何使用HTML佣工knockout.js

这很简单:

  @ Html.TextBoxFor(型号=&GT; model.CourseId,新{data_bind =值:CourseId})

其中:


  • 值:CourseId 表示绑定的输入财产从模型中的 CourseId 财产和你的脚本模型
  • 控制

的结果是:

 &LT;输入数据绑定=值:CourseId数据-VAL =真正的数据-VAL-数=这个领域CourseId必须是一个数字。数据-VAL-所需=是必需的CourseId场。 ID =CourseIdNAME =CourseId类型=文本值=12/&GT;

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

为什么你需要使用就绪事件序列模型我不明白的是,但它似乎仅仅是需要的(不用担心它虽然)

我如何做这样的事情,如果我用我的观点车型淘汰赛映射?由于我没有一个函数,由于映射。

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

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

 功能视图模型(){
    this.addStudent =功能(){
        警报(德);
    };
};$(函数(){
    VAR jsonModel ='@ Html.Raw(JsonConvert.SerializeObject(this.Model))';
    VAR mvcModel = ko.mapping.fromJSON(jsonModel);    VAR myViewModel =新视图模型();
    变种G = ko.mapping.fromJS(myViewModel,mvcModel);    ko.applyBindings(G);
});

关于警告你receiveing​​


  

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


您需要使用引号

与ko.editable插件

兼容性

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

  ko.editable(G);
    ko.applyBindings(G);

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

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

然后我必须提交和取消按钮具有以下code:

  this.executeCommit =功能(){
        this.commit();
        this.isInEditMode(假);
    };
    this.executeRollback =功能(){
        如果(this.hasChanges()){
            如果(确认(你确定要放弃更改?)){
                this.rollback();
                this.isInEditMode(假);
            }
        }
        其他{
            this.rollback();
            this.isInEditMode(假);
        }
    };

最后,我有一个字段,用于指示是否领域处于编辑模式与否,这只是启用属性绑定。

  this.isInEditMode = ko.observable(假);

有关阵列的问题


  

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


  
  

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


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

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

掘金:

的。

控制器code

  [HTTPGET]
    公众的ActionResult指数()
    {
        变种M =新CourseVM {CourseId = 12,课程名=净};        m.StudentViewModels.Add(新StudentVm {ID = 545,名称=,姓氏=上次从服务器名称,从服务器名称});        返回查看(米);
    }    [HttpPost]
    公众的ActionResult指数(CourseVM模型)
    {
        如果(!string.IsNullOrWhiteSpace(model.StudentsSerialized))
        {
            model.StudentViewModels = JsonConvert.DeserializeObject&LT;名单,LT; StudentVm&GT;&GT;(model.StudentsSerialized);
            model.StudentsSerialized =的String.Empty;
        }        如果(!string.IsNullOrWhiteSpace(model.SelectedStudentsSerialized))
        {
            model.SelectedStudents = JsonConvert.DeserializeObject&LT;名单,LT; StudentVm&GT;&GT;(model.SelectedStudentsSerialized);
            model.SelectedStudentsSerialized =的String.Empty;
        }        返回查看(模型);
    }

模型

 公共类CourseVM
{
    公共CourseVM()
    {
        this.StudentViewModels =新的List&LT; StudentVm&GT;();
        this.SelectedStudents =新的List&LT; StudentVm&GT;();
    }    公众诠释CourseId {搞定;组; }    [必需(的ErrorMessage =课程名称是必需)]
    [StringLength(100的ErrorMessage =课程名称不可能长久的。)
    公共字符串课程名{获得;组; }    公开名单&LT; StudentVm&GT; StudentViewModels {搞定;组; }
    公开名单&LT; StudentVm&GT; SelectedStudents {搞定;组; }    公共字符串StudentsSerialized {搞定;组; }
    公共字符串SelectedStudentsSerialized {搞定;组; }
}公共类StudentVm
{
    公众诠释ID {搞定;组; }
    公共字符串名称{;组; }
    公共字符串姓氏{搞定;组; }
}

CSHTML页

  @using(Html.BeginForm())
{
    @ Html.ValidationSummary(真)
    &LT;&字段集GT;
        &LT;传奇&GT; CourseVM&LT; /传说&GT;        &LT; D​​IV&GT;
            &LT; D​​IV CLASS =编辑标记&GT;
                @ Html.LabelFor(型号=&GT; model.CourseId)
            &LT; / DIV&GT;
            &LT; D​​IV CLASS =主编场&GT;
                @ Html.TextBoxFor(型号=&GT; model.CourseId,新{data_bind =启用:isInEditMode,值:CourseId})
                @ Html.ValidationMessageFor(型号=&GT; model.CourseId)
            &LT; / DIV&GT;            &LT; D​​IV CLASS =编辑标记&GT;
                @ Html.LabelFor(型号=&GT; model.CourseName)
            &LT; / DIV&GT;
            &LT; D​​IV CLASS =主编场&GT;
                @ Html.TextBoxFor(型号=&GT; model.CourseName,新{data_bind =启用:isInEditMode,值:课程名})
                @ Html.ValidationMessageFor(型号=&GT; model.CourseName)
            &LT; / DIV&GT;
            &LT; D​​IV CLASS =编辑标记&GT;
                @ Html.LabelFor(型号=&GT; model.StudentViewModels);
            &LT; / DIV&GT;
            &LT; D​​IV CLASS =主编场&GT;                @ Html.ListBoxFor(
                    模型=&GT; model.StudentViewModels,
                    新的SelectList(this.Model.StudentViewModels,ID,姓名),
                    新
                    {
                        风格=宽度:37%;,
                        data_bind =启用:isInEditMode,选择:StudentViewModels,optionsText:名称,值:leftStudentSelected,事件:{DBLCLICK:moveFromLeftToRight}
                    }
                )
                @ Html.ListBoxFor(
                    模型=&GT; model.SelectedStudents,
                    新的SelectList(this.Model.SelectedStudents,ID,姓名),
                    新
                    {
                        风格=宽度:37%;,
                        data_bind =启用:isInEditMode,选择:SelectedStudents,optionsText:名称,值:rightStudentSelected,事件:{DBLCLICK:moveFromRightToLeft}
                    }
                )
            &LT; / DIV&GT;            @ Html.HiddenFor(型号=&GT; model.CourseId,新{data_bind =值:CourseId})
            @ Html.HiddenFor(型号=&GT; model.CourseName,新{data_bind =值:课程名})
            @ Html.HiddenFor(型号=&GT; model.StudentsSerialized,新{data_bind =值:StudentsSerialized})
            @ Html.HiddenFor(型号=&GT; model.SelectedStudentsSerialized,新{data_bind =值:SelectedStudentsSerialized})
        &LT; / DIV&GT;        &所述p为H.;
            &LT;输入类型=提交值=保存数据绑定=启用:isInEditMode()!/&GT;
            &LT;按键数据绑定=启用:isInEditMode(),点击:编辑模式&gt;编辑模式和LT; /按钮&GT;&LT; BR /&GT;
            &LT; D​​IV&GT;
                &LT;按键数据绑定=启用:isInEditMode,请点击:传递addStudent&gt;添加学生和LT; /按钮&GT;
                &LT;按键数据绑定=启用:hasChanges,请点击:executeCommit&GT;提交&LT; /按钮&GT;
                &LT;按键数据绑定=启用:isInEditMode,请点击:executeRollback&GT;取消&LT; /按钮&GT;
            &LT; / DIV&GT;
        &所述; / P&GT;
    &LT; /字段集&GT;
}

脚本

 &LT;脚本的src =@ Url.Content(〜/脚本/ jQuery的-1.7.2.min.js)TYPE =文/ JavaScript的&GT;&LT ; / SCRIPT&GT;
&LT;脚本的src =@ Url.Content(〜/脚本/淘汰赛2.1.0.js)TYPE =文/ JavaScript的&GT;&LT; / SCRIPT&GT;
&LT;脚本的src =@ Url.Content(〜/脚本/ knockout.mapping-latest.js)TYPE =文/ JavaScript的&GT;&LT; / SCRIPT&GT;
&LT;脚本的src =@ Url.Content(〜/脚本/ ko.editables.js)TYPE =文/ JavaScript的&GT;&LT; / SCRIPT&GT;&LT;脚本类型=文/ JavaScript的&GT;
    变种G = NULL;
    功能视图模型(){
        this.addStudent =功能(){
            this.StudentViewModels.push(新学生(25日,我的名字+新的Date(),我的姓));
            this.serializeLists();
        };
        this.serializeLists =功能(){
            this.StudentsSerialized(ko.toJSON(this.StudentViewModels));
            this.SelectedStudentsSerialized(ko.toJSON(this.SelectedStudents));
        };
        this.leftStudentSelected = ko.observable();
        this.rightStudentSelected = ko.observable();
        this.moveFromLeftToRight =功能(){
            this.SelectedStudents.push(this.leftStudentSelected());
            this.StudentViewModels.remove(this.leftStudentSelected());
            this.serializeLists();
        };
        this.moveFromRightToLeft =功能(){
            this.StudentViewModels.push(this.rightStudentSelected());
            this.SelectedStudents.remove(this.rightStudentSelected());
            this.serializeLists();
        };
        this.isInEditMode = ko.observable(假);
        this.executeCommit =功能(){
            this.commit();
            this.isInEditMode(假);
        };
        this.executeRollback =功能(){
            如果(this.hasChanges()){
                如果(确认(你确定要放弃更改?)){
                    this.rollback();
                    this.isInEditMode(假);
                }
            }
            其他{
                this.rollback();
                this.isInEditMode(假);
            }
        };
        this.editMode =功能(){
            this.isInEditMode(this.isInEditMode()!);
            this.beginEdit();
        };
    }    函数学生(ID,姓名,姓氏){
        this.ID = ID;
        this.Name =名称;
        this.LastName = lastName的;
    }    $(函数(){
        VAR jsonModel ='@ Html.Raw(JsonConvert.SerializeObject(this.Model))';
        VAR mvcModel = ko.mapping.fromJSON(jsonModel);        VAR myViewModel =新视图模型();
        G = ko.mapping.fromJS(myViewModel,mvcModel);        g.StudentsSerialized(ko.toJSON(g.StudentViewModels));
        g.SelectedStudentsSerialized(ko.toJSON(g.SelectedStudents));        ko.editable(G);
        ko.applyBindings(G);
    });
&LT; / SCRIPT&GT;

请注意:我只是说这些行:

  @ Html.HiddenFor(型号=&GT; model.CourseId,新{data_bind =值:CourseId})
        @ Html.HiddenFor(型号=&GT; model.CourseName,新{data_bind =值:课程名})

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

Bounty

It's been awhile and I still have a couple outstanding questions. I hope by adding a bounty maybe these questions will get answered.

  1. How do you use html helpers with knockout.js
  2. Why was document ready needed to make it work(see first edit for more information)

  3. How do I do something like this if I am using the knockout mapping with my view models? As I do not have a function due to the mapping.

    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. I want to use plugins for instance I want to be able to rollback observables as if a user cancels a request I want to be able to go back to the last value. From my research this seems to be achieved by people making plugins like editables

    How do I use something like that if I am using mapping? I really don’t want to go to a method where I have in my view manual mapping were I map each MVC viewMode field to a KO model field as I want as little inline javascript as possible and that just seems like double the work and that’s why I like that mapping.

  5. I am concerned that to make this work easy (by using mapping) I will lose a lot of KO power but on the other hand I am concerned that manual mapping will just be a lot of work and will make my views contain too much information and might become in the future harder to maintain(say if I remove a property in the MVC model I have to move it also in the KO viewmodel)


Original Post

I am using asp.net mvc 3 and I looking into knockout as it looks pretty cool but I am having a hard time figuring out how it works with asp.net mvc especially view models.

For me right now I do something like this

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

}

I would have a Vm that has some basic properties like CourseName and it will have some simple validation on top of it. The Vm model might contain other view models in it as well if needed.

I would then pass this Vm to the View were I would use html helpers to help me display it to the user.

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

I might have some foreach loops or something to get the data out of the collection of Student View Models.

Then when I would submit the form I would use jquery and serialize array and send it to a controller action method that would bind it back to the viewmodel.

With knockout.js it is all different as you now got viewmodels for it and from all the examples I seen they don't use html helpers.

How do you use these 2 features of MVC with knockout.js?

I found this video and it briefly(last few minutes of the video @ 18:48) goes into a way to use viewmodels by basically having an inline script that has the knockout.js viewmodel that gets assigned the values in the ViewModel.

Is this the only way to do it? How about in my example with having a collection of viewmodels in it? Do I have to have a foreach loop or something to extract all the values out and assign it into knockout?

As for html helpers the video says nothing about them.

These are the 2 areas that confuses the heck out of me as not many people seem to talk about it and it leaves me confused of how the initial values and everything is getting to the view when ever example is just some hard-coded value example.


Edit

I am trying what Darin Dimitrov has suggested and this seems to work(I had to make some changes to his code though). Not sure why I had to use document ready but somehow everything was not ready without it.

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

I had to wrap it around a jquery document ready to make it work.

I also get this warning. Not sure what it is all about.

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

So I have a starting point I guess at least will update when I done some more playing around and how this works.

I am trying to go through the interactive tutorials but use the a ViewModel instead.

Not sure how to tackle these parts yet

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

or

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


Edit 2

I been able to figure out the first problem. No clue about the second problem. Yet though. Anyone got any ideas?

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

Controller

  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);
    }

解决方案

I think I have summarized all your questions, if I missed something please let me know (If you could summarize up all your questions in one place would be nice =))

Note. Compatibility with the ko.editable plug-in added

Download the full code

How do you use html helpers with knockout.js

This is easy:

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

Where:

  • value: CourseId indicates that you are binding the value property of the input control with the CourseId property from your model and your script model

The result is:

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

Why was document ready needed to make it work(see first edit for more information)

I do not understand yet why you need to use the ready event to serialize the model, but it seems that it is simply required (Not to worry about it though)

How do I do something like this if I am using the knockout mapping with my view models? As I do not have a function due to the mapping.

If I understand correctly you need to append a new method to the KO model, well that's easy merging models

For more info, in the section -Mapping from different sources-

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);
});

About the warning you were receiveing

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

You need to use quotes

Compatibility with the ko.editable plug-in

I thought it was going to be more complex, but it turns out that the integration is really easy, in order to make your model editable just add the following line: (remember that in this case I am using a mixed model, from server and adding extension in client and the editable simply works... it's great):

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

From here you just need to play with your bindings using the extensions added by the plug-in, for example, I have a button to start editing my fields like this and in this button I start the edit process:

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

Then I have commit and cancel buttons with the following code:

    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);
        }
    };

And finally, I have one field to indicate whether the fields are in edit mode or not, this is just to bind the enable property.

this.isInEditMode = ko.observable(false);

About your array question

I might have some foreach loops or something to get the data out of the collection of Student View Models.

Then when I would submit the form I would use jquery and serialize array and send it to a controller action method that would bind it back to the viewmodel.

You can do the same with KO, in the following example, I will create the following output:

Basically here, you have two lists, created using Helpers and binded with KO, they have a dblClick event binded that when fired, remove the selected item from the current list and add it to the other list, when you post to the Controller, the content of each list is sent as JSON data and re-attached to the server model

Nuggets:

External scripts.

Controller code

    [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);
    }

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 page

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

Scripts

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

Note: I just added these lines:

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

Because when I submit the form my fields are disabled, so the values were not transmitted to the server, that's why I added a couple of hidden fields to do the trick

这篇关于如何使用knockout.js在ASP.NET MVC中的ViewModels?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆