วิธีใช้ knockout.js กับ ASP.NET MVC ViewModels?


129

เงินรางวัล

มันไม่นานมานี้และฉันยังมีคำถามที่ค้างอยู่สองสามข้อ ฉันหวังว่าโดยการเพิ่มรางวัลบางทีคำถามเหล่านี้จะได้รับคำตอบ

  1. คุณใช้ html helpers กับ knockout.js อย่างไร
  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. ฉันต้องการใช้ปลั๊กอินเช่นฉันต้องการสามารถย้อนกลับ observables ราวกับว่าผู้ใช้ยกเลิกการร้องขอฉันต้องการที่จะสามารถกลับไปที่ค่าสุดท้าย จากการวิจัยของฉันสิ่งนี้น่าจะเกิดขึ้นได้จากการที่คนทำปลั๊กอินอย่างที่สามารถแก้ไขได้

    ฉันจะใช้บางอย่างเช่นนี้ได้อย่างไรถ้าฉันใช้แผนที่? ฉันไม่ต้องการไปที่วิธีการที่ฉันมีในการทำแผนที่มุมมองด้วยตนเองคือฉันทำแผนที่แต่ละฟิลด์ MVC viewMode ไปยังเขตข้อมูลโมเดล KO เพราะฉันต้องการจาวาสคริปต์แบบอินไลน์เล็ก ๆ น้อย ๆ เท่าที่จะทำได้ ทำไมฉันถึงชอบแผนที่นั้น

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

}

ฉันจะมี Vm ที่มีคุณสมบัติพื้นฐานบางอย่างเช่น CourseName และจะมีการตรวจสอบง่าย ๆ อยู่ด้านบน โมเดล Vm อาจมีโมเดลมุมมองอื่น ๆ เช่นกันหากจำเป็น

จากนั้นฉันจะส่ง Vm นี้ไปยังมุมมองฉันจะใช้ผู้ช่วย html เพื่อช่วยแสดงให้ผู้ใช้เห็น

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

ฉันอาจมีลูป foreach หรืออะไรบางอย่างเพื่อดึงข้อมูลออกมาจากคอลเลกชันของ Student View Models

จากนั้นเมื่อฉันจะส่งแบบฟอร์มฉันจะใช้ jquery และserialize arrayส่งไปยังวิธีการดำเนินการของตัวควบคุมที่จะผูกกลับไปที่ viewmodel

ด้วย knockout.js มันแตกต่างอย่างสิ้นเชิงเมื่อคุณได้รับ viewmodels สำหรับมันและจากตัวอย่างทั้งหมดที่ฉันเห็นพวกเขาไม่ได้ใช้ตัวช่วย html

คุณจะใช้คุณสมบัติ 2 อย่างของ MVC กับ knockout.js ได้อย่างไร

ฉันพบวิดีโอนี้และสั้น ๆ (ไม่กี่นาทีสุดท้ายของวิดีโอ @ 18:48) ไปสู่วิธีการใช้ viewmodels โดยทั่วไปมีสคริปต์แบบอินไลน์ที่มีรูปแบบ knockout.js ที่ได้รับการกำหนดค่าใน ViewModel

นี่เป็นวิธีเดียวที่จะทำได้หรือไม่? ในตัวอย่างของฉันเกี่ยวกับการมีคอลเลกชันของวิวโหมดในนั้น ฉันจะต้องมีวง foreach หรือสิ่งที่จะแยกค่าทั้งหมดออกและกำหนดให้เป็นสิ่งที่น่าพิศวง?

ในฐานะที่เป็นผู้ช่วย HTML วิดีโอไม่ได้พูดอะไรเกี่ยวกับพวกเขา

นี่เป็นพื้นที่ 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));


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

ดังนั้นฉันจึงมีจุดเริ่มต้นฉันเดาว่าอย่างน้อยก็จะอัปเดตเมื่อฉันเล่นต่อไปอีกรอบ

ฉันกำลังพยายามผ่านบทช่วยสอนแบบโต้ตอบ แต่ใช้ ViewModel แทน

ยังไม่แน่ใจว่าจะจัดการส่วนเหล่านี้อย่างไร

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

2
ฉันเพิ่งเขียนโพสต์บล็อกเพื่อตอบคำถามที่คล้ายกันอื่น: roysvork.wordpress.com/2012/12/09/..อาจไม่ตอบคำถามของคุณได้อย่างสมบูรณ์ แต่มันก็ช่วยให้คุณมีความคิดที่ดีว่าสิ่งต่าง ๆ สามารถทำงานได้อย่างไร ฉันหวังว่าจะติดตามเรื่องนี้พร้อมโพสต์ต่อไปในอนาคตอันใกล้ อย่าลังเลที่จะถามคำถามใด ๆ ในความคิดเห็นในโพสต์หรือที่นี่หากคุณต้องการข้อมูลเพิ่มเติม
เกินรหัส

คำตอบ:


180

ฉันคิดว่าฉันได้สรุปคำถามทั้งหมดของคุณแล้วหากฉันพลาดบางสิ่งโปรดแจ้งให้เราทราบ ( หากคุณสามารถสรุปคำถามทั้งหมดของคุณได้ในที่เดียวน่าจะดี =))

บันทึก. เข้ากันได้กับko.editableปลั๊กอินที่เพิ่มเข้ามา

ดาวน์โหลดรหัสเต็ม

คุณใช้ html helpers กับ knockout.js อย่างไร

นี่เป็นเรื่องง่าย:

@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 นั่นคือรูปแบบที่รวมกันเป็นเรื่องง่าย

สำหรับข้อมูลเพิ่มเติมในส่วน - การแมปจากแหล่งต่าง ๆ -

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

เกี่ยวกับคำเตือนที่คุณได้รับ

คำเตือน 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 หรืออะไรบางอย่างเพื่อดึงข้อมูลออกมาจากคอลเลกชันของ Student View Models

จากนั้นเมื่อฉันจะส่งแบบฟอร์มฉันจะใช้ jquery และจัดลำดับอาร์เรย์และส่งไปยังวิธีการดำเนินการของตัวควบคุมที่จะผูกกลับไปที่ viewmodel

คุณสามารถทำเช่นเดียวกันกับ KO ในตัวอย่างต่อไปนี้ฉันจะสร้างผลลัพธ์ต่อไปนี้:

ป้อนคำอธิบายรูปภาพที่นี่

โดยพื้นฐานแล้วที่นี่คุณมีสองรายการสร้างโดยใช้Helpersและผูกกับ KO พวกเขามีdblClickเหตุการณ์ที่ผูกไว้ว่าเมื่อถูกไล่ออกลบรายการที่เลือกจากรายการปัจจุบันและเพิ่มไปยังรายการอื่นเมื่อคุณโพสต์ไปControllerที่เนื้อหาของแต่ละรายการ รายการจะถูกส่งเป็นข้อมูล JSON และแนบกับโมเดลเซิร์ฟเวอร์อีกครั้ง

นักเก็ต:

ภายนอกสคริปต์

รหัสคอนโทรลเลอร์

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

เพราะเมื่อฉันส่งแบบฟอร์มเขตข้อมูลของฉันถูกปิดใช้งานดังนั้นค่าจึงไม่ถูกส่งไปยังเซิร์ฟเวอร์นั่นคือเหตุผลที่ฉันเพิ่มสองเขตข้อมูลที่ซ่อนอยู่เพื่อทำเคล็ดลับ


อืมข้อมูลมาก จากคำตอบของคุณและคำตอบของ Pual ฉันคิดว่าฉันเกือบจะได้รับคำตอบของคำถามทั้งหมดยกเว้นวิธีใช้ปลั๊กอินอย่างที่แก้ไขได้ หวังว่าใครบางคนรู้ว่าฉันสามารถใช้สิ่งนี้ได้อย่างไร
chobo2

1
ฉันเพิ่งเพิ่มความเข้ากันได้กับko.editablesปลั๊กอินคุณสามารถตรวจสอบการตอบสนองที่อัปเดตหรือถ้าคุณต้องการคุณสามารถดาวน์โหลดโครงการทั้งหมดเพื่อเรียกใช้ในเครื่อง
Jupaol

ฉันจะตรวจสอบออกเมื่อฉันสามารถ ต้องเปลี่ยนอะไรบ้างเพื่อให้มันทำงาน? ฉันสงสัยว่าสำหรับทุกปลั๊กอินฉันพบว่าฉันจะต้องมีการเปลี่ยนแปลงมันและจากนั้นจะต้องเก็บรุ่นของตัวเอง
chobo2

Nope คุณจะประหลาดใจมันใกล้จะถึงแล้ว
Jupaol

1
ขอบคุณมัดฉันได้เรียนรู้กลยุทธ์ใหม่ ๆ จากการตอบสนองของคุณ รุ่งโรจน์!
sky-dev

23

คุณสามารถทำให้รูปแบบมุมมอง ASP.NET MVC เป็นอนุกรมเป็นตัวแปรจาวาสคริปต์:

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

มีตัวอย่างมากมายในเอกสารประกอบที่น่าพิศวงที่คุณสามารถทำได้


1
ใช่ฉันผ่านการสอนแบบอินเทอร์แอคทีฟบนเว็บไซต์ แต่ฉันไม่เคยเห็นเกี่ยวกับ asp.net mvc เลย ฉันเห็นว่าพวกเขายังมีปลั๊กอินการแมปด้วยเช่นกัน แต่ไม่แน่ใจว่ามันเข้ากันได้อย่างไรในตัวอย่างของคุณคุณจะผูกมันเข้ากับโมเดลที่น่าพิศวงได้อย่างไร (ในสคริปต์อื่น) ฉันต้องการที่จะมีจาวาสคริปต์แบบอินไลน์ให้น้อยที่สุดเท่าที่จะเป็นไปได้ (ไม่ใช่ตัวเลือกที่ดีกว่า แต่ฉันคิดว่ามันเป็นไปไม่ได้)
chobo2

2
คุณกำลังพยายามแก้ไขปัญหาอะไร หากคุณต้องการมุมมอง MVC และมีความสุขกับวิธีการใช้งานคุณสามารถติดที่นั่นได้ หากคุณต้องการเชื่อมโยงและจัดการข้อมูลฝั่งไคลเอ็นต์ KO เป็นตัวเลือกที่ยอดเยี่ยม คุณสามารถสร้าง KO viewmodel ของคุณจากรหัส MVC ของคุณตามคำตอบนี้ มันใช้ vm และทำให้เป็นอนุกรมเพื่อ json จากนั้นในไคลเอนต์คุณสามารถแมปผลลัพธ์กับ javascript viewmodel จากนั้นเชื่อมโยง viewmodel กับมุมมองและคุณพร้อมแล้ว กุญแจสำคัญคือ MVC และ KO ไม่จำเป็นต้องเชื่อมต่อด้วยวิธีใด ๆ เว้นแต่คุณต้องการให้เป็น ทั้งหมดขึ้นอยู่กับปัญหาที่คุณพยายามแก้ไข
John Papa

1
เป็นเรื่องปกติที่คุณจะไม่เห็นสิ่งใดที่เกี่ยวข้องกับ asp.net mvc สิ่งที่น่าพิศวงเป็นกรอบด้านลูกค้า ไม่ทราบว่าไม่สนใจภาษาฝั่งเซิร์ฟเวอร์ที่คุณใช้ กรอบทั้งสองนั้นควรถูกแยกออกอย่างแน่นอน
ดารินทินดิมิทรอฟ

@ JohnPapa - ฉันชอบวิธีที่ฉันทำสิ่งต่าง ๆ ในตอนนี้ แต่ฉันก็ชอบเรียนรู้สิ่งใหม่ ๆ ด้วย (ฉันเห็นว่า KO มีประโยชน์มากในบางสถานการณ์) ฉันรู้ว่า KO เป็นสคริปต์ฝั่งไคลเอ็นต์ แต่สำหรับฉันฉันเห็นพวกเขาทำงานร่วมกัน ขณะนี้ฉันสร้างมุมมองของฉันโดยใช้โมเดลการดูและตัวช่วย html ดังนั้นในความคิดของฉัน KO จำเป็นต้องทำงานร่วมกับสิ่งนี้ ตัวอย่างเช่นสมมติว่าคุณได้รับกล่องโต้ตอบแก้ไข คุณจะออกแบบและเติมค่าจากฐานข้อมูลลงในฟิลด์เหล่านั้นอย่างไร ถ้าฉันใช้วิธีของฉันมันจะเป็นมุมมองของผู้ช่วย html ที่มี viewModel จะเติม viewmodel และส่งผ่านวิธีการดำเนินการและใช้งาน
chobo2

1
@ chobo2, สิ่งที่น่าพิศวงเป็นกรอบด้านลูกค้า มันใช้มุมมองแบบจำลองบนไคลเอนต์เพื่อใช้รูปแบบ MVC บนไคลเอนต์ เซิร์ฟเวอร์ถูกแยกออก คุณสามารถใช้โมเดลการดูด้วย มันเป็นแค่ 2 แห่งที่ต่างกัน หากคุณมีตรรกะที่ซับซ้อนบางอย่างที่คุณต้องการนำไปใช้กับลูกค้าโดยใช้จาวาสคริปต์แล้วสิ่งที่น่าพิศวงสามารถทำให้สิ่งนี้ง่ายขึ้น ไม่อย่างนั้นคุณไม่ต้องการมัน
ดารินทินดิมิทรอฟ

2

เพื่อให้ได้คุณสมบัติที่คำนวณเพิ่มเติมหลังจากการแมปเซิร์ฟเวอร์คุณจะต้องปรับปรุงมุมมองโมเดลของคุณเพิ่มเติมในฝั่งไคลเอ็นต์

ตัวอย่างเช่น:

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

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

ดังนั้นทุกครั้งที่คุณแมปจาก JSON แบบดิบคุณจะต้องใช้คุณสมบัติที่คำนวณใหม่อีกครั้ง

นอกจากนี้ปลั๊กอินการแมปยังให้ความสามารถในการปรับปรุง viewmodel ที่เพิ่มขึ้นเมื่อเทียบกับการสร้างใหม่ทุกครั้งที่คุณกลับไปกลับมา (ใช้พารามิเตอร์เพิ่มเติมในfromJS):

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

และนั่นก็เป็นการประมวลผลการอัพเดทข้อมูลที่เพิ่มขึ้นบนโมเดลของคุณสมบัติที่แมป คุณสามารถอ่านเพิ่มเติมเกี่ยวกับสิ่งนั้นได้ในเอกสารการทำแผนที่

คุณพูดถึงในความคิดเห็นเกี่ยวกับดารินว่าตอบแพ็คเกจFluentJSON ฉันเป็นผู้เขียน แต่กรณีการใช้นั้นเฉพาะเจาะจงกว่า ko.mapping โดยทั่วไปฉันจะใช้เฉพาะเมื่อ viewmodels ของคุณเป็นวิธีเดียว (เช่น. เซิร์ฟเวอร์ -> ไคลเอนต์) จากนั้นข้อมูลจะถูกโพสต์กลับในรูปแบบที่แตกต่างกัน (หรือไม่เลย) หรือถ้า javascript viewmodel ของคุณจำเป็นต้องอยู่ในรูปแบบที่แตกต่างอย่างมากจากรูปแบบเซิร์ฟเวอร์ของคุณ


อืมฉันคิดว่าบางที FluentJSON ไม่ใช่ของฉันเพราะมุมมองของฉันส่วนใหญ่ใช้เวลาทั้งสองทาง (ฉันมักจะส่งมันกลับผ่าน json แล้วผูกมันไว้กับ viewmodel ในพารามิเตอร์วิธีการกระทำ) คุณรู้หรือไม่ว่าฉันจะใช้ปลั๊กอินที่ฉันกล่าวถึงเช่นสามารถแก้ไขได้? ในที่สุดฉันก็สูญเสียฟังก์ชันการทำงานใด ๆ โดยใช้การแมปและพยายามใช้ viewmodel ของฉันเทียบกับที่ไม่ได้ใช้งานหรือไม่
chobo2

ฉันไม่ได้ใช้ปลั๊กอินเลยไม่แน่ใจ สิ่งที่ฉันทำในอดีตคือการสมัครรับการเปลี่ยนแปลงทุกครั้งและเก็บสแต็คของ viewmodel ที่ต่อเนื่องกันซึ่งฉันจะผลักดันให้เกิดการเปลี่ยนแปลงและป๊อปอัปในการเลิกทำ ( ดูคำถามนี้ )
Paul Tyng

การทำแผนที่ไม่ได้ป้องกันคุณจากการทำงานใด ๆ คุณเพียงแค่ต้องตรวจสอบและปฏิบัติตามอนุสัญญาว่าด้วยวิธีการจัดการการแมปไปยังและจาก JS เพื่อให้การเล่นทั้งหมดเข้าด้วยกันเป็นอย่างดี
Paul Tyng

คำตอบที่ได้รับการยอมรับสำหรับคำถามที่คุณโพสต์นั้นเป็นสิ่งที่ปลั๊กอินจะต้องมี นั่นคือสิ่งที่ทำให้ฉันสับสนอย่างที่คุณเห็นพวกเขาสร้างโมเดลจากนั้นใช้ฟังก์ชั่นที่พวกเขาสร้างขึ้น (ko.observableArrayWithUndo ([])) ถ้าฉันทำแผนที่ฉันไม่รู้ว่าจะทำอย่างไร สิ่งเดียวที่อยู่ในใจคือการเขียนการแมปของตัวเอง (สิ่งที่ฉันสงสัยว่าฉันสามารถทำได้ในเวลานี้) ที่มีการยกเลิกการสังเกตหรือแมปคุณสมบัติแต่ละแห่ง แต่โดยทั่วไปแล้วฉันมีมุมมองที่ซ้ำกันสำหรับฝั่งเซิร์ฟเวอร์ กลัวว่าจะไม่สามารถรักษาได้
chobo2

อ่าใช่ฉันขอโทษที่ฉันพูดถึงคำตอบของฉันสำหรับคำถามนั้นขออภัยควรมีการเชื่อมโยงโดยตรง
Paul Tyng
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.