在MVC视图中使用Knockout多次生成和跟踪同一模板​​?

时间:2016-01-28 16:15:34

标签: javascript jquery asp.net-mvc twitter-bootstrap knockout.js

我整理了一个使用Knockoutjs的Contacts原型MVC应用程序。我对Knockout很新,并且想知道我的设计在达到我的最终目标时是否正确。我的最终目标基本上是采用传递给我的Contacts视图的MVC模型来启动并实现以下目标:

  • 将其映射到我的KO Viewmodel。
  • 使用Bootstrap Modal Popup输入我的联系人数据。
  • 在发布JSON后单击Add in Bootstrap Modal调用模板 数据到控制器成功并显示在
  • 在div下呈现的每个模板上的“编辑”按钮,如果单击,则会显示相同的“模态弹出”以编辑模板数据。

这是我目前所处的代码细分。

查看代码

    <h2>Contacts List</h2>

    <div class="row">
        <div class="col-lg-2"></div>
        <div class="col-lg-10"><h3>KO Results</h3></div>
    </div>
    <br />
    <div class="row">
        <div class="col-lg-2"></div>
        <div class="col-lg-10"><div id="koResults" data-bind="template: { name: 'contactSectionTmp', foreach:Contacts }"></div></div>
    </div>
    <div class="row">
        <div class="col-lg-2"></div>
        <div class="col-lg-10"><a href="#" id="addContact" class="btn btn-sm btn-success" data-toggle="modal" data-target="#contactModal" data-bind="click: addContact"><strong>Add</strong></a></div>
    </div>

     @*I enter data in my bootstrap modal shown below and when I click "Add" the Template below appears
        in div element koResults with the data I just entered. This is the desired effect I'm looking for. *@

 <div class="modal" id="contactModal" tabindex="-1" role="dialog" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header" style="background-color:#B8E28D; border-color: black">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                <h4 class="modal-title" id="myModalLabel">Add Contact</h4>
            </div>
            <div class="form-horizontal">
                <form id="contactModalForm" data-bind="with:newContact,submit:add">
                    <div class="modal-body">
                        <h4>Contact</h4>
                        <div class="form-group">
                            <label class="col-sm-4 control-label">Name:</label>
                            <div class="col-sm-8">
                                <input type="text" name="Name" class="form-control" data-bind="value: Name" />
                            </div>
                        </div>
                        <div class="form-group">
                            <label class="col-sm-4 control-label">Address:</label>
                            <div class="col-sm-8">
                                <textarea rows="4" cols="50" name="Address" class="form-control" data-bind="value: Address"></textarea>
                            </div>
                        </div>
                        <div class="form-group">
                            <label class="col-sm-4 control-label">Phone:</label>
                            <div class="col-sm-8">
                                <input type="text" name="Phone" class="form-control" data-bind="value: Phone" />
                            </div>
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="submit" id="formSubmitContact" class="btn btn-success">Add</button>
                        <button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>


@section scripts

    <script type="text/javascript" src="~/Scripts/knockout-3.4.0.debug.js"></script>
    <script type="text/javascript" src="~/Scripts/knockout.mapping-latest.debug.js"></script>


    @* Knockout Template *@
    <script id="contactSectionTmp" type="text/html">
        <div class="row">
            <div class="col-lg-3">Name:</div>
            <div class="col-lg-9" data-bind="text: name"></div>
        </div>
        <div class="row">
            <div class="col-lg-3">Address:</div>
            <div class="col-lg-9" data-bind="text: address"></div>
        </div>
        <div class="row">
            <div class="col-lg-3">Phone:</div>
            <div class="col-lg-9" data-bind="text: phone"></div>
        </div>
    </script>

End Section

控制器代码

    Pass in model to view here.
    public ActionResult ContactsList()
    {
        ContactsVM mData = new ContactsVM();

        mData.Contacts = new List<Contact>(){ new Contact { ID = 1, Name="Drew Lucacca", Address="782 Select St.", Phone="421-821-9101"},
            new Contact {ID = 2, Name="Kevin Rosassa", Address = "222 Potter Lane", Phone="421-982-5222" },
            new Contact {ID = 3, Name="Tim Kropp", Address = "440 PPG Place", Phone="725-434-8989"} };

        return View(mData);
    }

    [HttpPost]
    public ActionResult ContactCreate(Contact newContact)
    {

        var res = newContact;

        ContactsVM myContacts = new ContactsVM();
        myContacts.Contacts = new List<Contact>();

        myContacts.Contacts.Add(new Contact { ID = 4, Name = "Santa Claus", Address = "440 Trump Plaza", Phone = "774-489-8989" });

        return Json(myContacts);
    }

Javascript代码

`        //Main ViewModel
        function ContactsVM(data) {

            var self = this;

            var mapping = {
                'Contacts': {
                    create: function(options) {
                        return new Contact(options.data);
                    }
                }
            };

            ko.mapping.fromJS(data, mapping, self);

            self.newContact = ko.observable();

            self.addContact = function() {
                debugger;
                self.newContact(new Contact({Name: '', Address: '', Phone: ''}));
            }

            self.add = function () {
                debugger;
                var jsData = data;
                var jsData1 = ko.mapping.toJSON(self.newContact());

                $.ajax({
                    url: '@Url.Action("ContactCreate", "Home")',
                    type: 'POST',
                    data: ko.mapping.toJSON(self.newContact()),
                    dataType: 'json',
                    contentType: 'application/json; charset=utf-8',
                    success: function (jsonObject) {
                        self.contacts.push(new Contact(jsonObject));
                    }
                });

                // Close the modal.
                $('#contactModal').modal('toggle');
            };


            self.cancel = function () {

                // Close the modal.
                $('#contactModal').modal('toggle');
            };

            //self.resetForm = function (formId) {
            //    var form = $('#' + formId);
            //    form.validate().resetForm();
            //    form.get(0).reset();
            //};



};

    function Contact(data) {
        ko.mapping.fromJS(data, {}, this);
        this.isEdit = ko.observable(false);
    };


$(function () {

    var jsonModel = @Html.Raw(Newtonsoft.Json.JsonConvert.SerializeObject(this.Model));

    var vm = new ContactsVM(jsonModel);
    ko.applyBindings(vm);

    });

联系实体

public class Contact
{
    public int ID { get; set; }
    public string Name { get; set; }
    public string Address { get; set; }
    public string Phone { get; set; }
}

ContactsVM实体

public class ContactsVM
{
    public List<Contact>  Contacts { get; set; }
}

编辑#1 看到这里我知道javascript是不正确的,并注意在javascript评论中询问您是否可以帮助我确定它是否不正确应该如何。

我将代码移动到MVC视图底部的新位置,因为Javascript代码似乎找不到模型。

Javascript - 淘汰赛 - 映射错误

JavaScript运行时错误:&#39;推送&#39;未定义

self.contacts.push(new Contact(jsonObject)); &LT; ---这里发生了错误。

这里的任何帮助都将非常感谢,我相信也会帮助其他人。

1 个答案:

答案 0 :(得分:0)

我认为根据您列出的步骤,您可能最好采用迭代方法来实现此功能。一次做一件事,让它工作,然后继续下一个项目。试图一次性解决所有问题并完全测试它是非常困难的。

第一推荐:让您的客户端模型反映您的服务器端模型。之后,事情变得更容易了。由于您使用的是ko映射,因此您的客户端模型设置变得更加容易:

var web = new HttpListener();

    web.Prefixes.Add("http://www.dfdfdfdfdfd.com/");

    Console.WriteLine("Listeningg..");

    web.Start();

    Console.WriteLine(web.GetContext());

    var context = web.GetContext();

    var response = context.Response;

    const string responseString = "<html><body>Hello world</body></html>";

    var buffer = System.Text.Encoding.UTF8.GetBytes(responseString);

    response.ContentLength64 = buffer.Length;

    var output = response.OutputStream;

    output.Write(buffer, 0, buffer.Length);

    Console.WriteLine(output);

    output.Close();

    web.Stop();

    Console.ReadKey();

然后您也可以非常轻松地创建和应用顶级视图模型:

function ContactsVM(data) {
  var mapping = {
    'Contacts': {
      create: function(options) {
        return new Contact(options.data);
      }
    }
  };

  ko.mapping.fromJS(data, mapping, this);
  this.newContact = ko.observable();
}

function Contact(data) {
  ko.mapping.fromJS(data, {}, this);
  this.isEdit = ko.observable(false);
}

这为您提供了一个顶级视图模型,其中包含一个完全填充的Contacts observable数组属性。您可以使用模式的newContact属性添加新联系人,只需使用新的Contact实例填充它。

  var vm = new ContactsVM(jsonModel);
  ko.applyBindings(vm);

当您将此新联系人推送到联系人数组时,DOM将自动更新以显示新联系人,因此您不需要使用&#34; ko.renderTemplate&#34;您指定的逻辑。我想你也可以根据这个observable是否有一个值显示/隐藏模态。

第二个建议:首先尝试使用淘汰赛,如果你不能使用jQuery。我不建议使用jQuery来序列化表单值。请记住,您可以直接访问客户端模型,因此您不再依赖于DOM。 ko映射插件有一个方法{{3}}回到常规的JS对象。