KnockOutJS - ViewModels หลายรายการในมุมมองเดียว


201

ฉันคิดว่าแอปพลิเคชันของฉันมีขนาดค่อนข้างใหญ่ในขณะนี้มีขนาดใหญ่เกินไปที่จะจัดการแต่ละมุมมองด้วย ViewModel เดียว

ดังนั้นฉันจึงสงสัยว่าจะสร้าง ViewModels หลายรายการและโหลดทั้งหมดลงในมุมมองเดียวได้อย่างไร ด้วยหมายเหตุที่ฉันยังต้องสามารถส่งผ่านข้อมูลX ViewModelไปยังข้อมูลY ViewModelดังนั้น ViewModels แต่ละรายการจะต้องสามารถสื่อสารระหว่างกันหรืออย่างน้อยก็ต้องระวังซึ่งกันและกัน

ตัวอย่างเช่นฉันมีรายการ<select>แบบหล่นลงที่เลือกแบบเลื่อนลงมีสถานะที่เลือกซึ่งช่วยให้ฉันผ่าน ID ของรายการที่เลือกในการ<select>โทร Ajax อื่นใน ViewModel แยกต่างหาก ....

จุดใด ๆ ในการจัดการกับ ViewModels จำนวนมากในมุมมองเดียวชื่นชม :)


12
สำหรับผู้ที่มาถึงคำถามนี้โปรดเลื่อนผ่านคำตอบที่ยอมรับ สิ่งที่น่าพิศวงในขณะนี้สนับสนุนแวดล้อมที่มีผลผูกพันหลาย masterVMไม่มีความจำเป็นสำหรับยักษ์ไม่เป็น
Carrie Kendall

คำตอบ:


150

หากพวกเขาทั้งหมดต้องอยู่ในหน้าเดียวกันวิธีที่ง่ายวิธีหนึ่งคือการมีโมเดลมุมมองต้นแบบที่มีอาร์เรย์ (หรือรายการคุณสมบัติ) ของโมเดลมุมมองอื่น

masterVM = {
    vmA : new VmA(),
    vmB : new VmB(),
    vmC : new VmC(),
}

จากนั้นคุณmasterVMสามารถมีคุณสมบัติอื่น ๆ หากจำเป็นสำหรับหน้าตัวเอง การสื่อสารระหว่างมุมมองโมเดลจะไม่ยากในสถานการณ์นี้เนื่องจากคุณสามารถถ่ายทอดผ่านmasterVMหรือคุณสามารถใช้$parent/ $rootในการผูกหรือตัวเลือกที่กำหนดเองอื่น ๆ


2
ดังนั้นฉันจะสามารถทำสิ่งที่ชอบ: data-bind = "text: masterVM.vmA" ฉันคิดว่าฉันยังคงสามารถใช้ ko.applyBindings พร้อมกับองค์ประกอบ DOM ที่แนบมา เข้าใจว่ายังหมายความว่าฉันสามารถทำได้: data-bind = "$ parent.masterVm"?
CLiown

12
@CLiown คุณสามารถใช้การwith:ผูกดังนั้นคุณจะไม่ทำซ้ำตัวเอง
AlfeG

4
@CLiown ใช่คุณสามารถทำเช่นนั้นได้หากผูกไว้กับ masterVM คุณยังสามารถใช้การเชื่อมโยง "กับ" เพื่อช่วยหลีกเลี่ยงไวยากรณ์จุดเมื่อคุณดำดิ่งลงในโมเดลมุมมองย่อย
John Papa

1
ฉันคิดว่าวิธีการนี้เป็นวิธีที่ จำกัด มาก ... ในกรณีของฉันฉันใช้ ASP.Net MVC4 นี่ไม่ได้ช่วยอะไรเพราะจะมีมุมมองบางส่วนที่มี ViewModels ของตัวเองและส่วน / เนื้อหาบางส่วนไม่ควรรบกวนซึ่งกันและกัน และเนื่องจากการเรนเดอร์แบบมีเงื่อนไขมันจะยากมากที่จะใช้วิธีนี้
bhuvin

1
@bhuvin โดยใช้ <! - ko stopBinding: true -> จะช่วยให้คุณมีโมเดลมุมมองหลายมุมมองและส่วนมุมมองบางส่วน ดูknockmeout.net/2012/05/quick-tip-skip-binding.htmlสำหรับข้อมูลเพิ่มเติม
MicaëlFélix

285

สิ่งที่น่าพิศวงตอนนี้รองรับการผูกหลายรูปแบบ ko.applyBindings()วิธีการใช้เวลาพารามิเตอร์ตัวเลือก - องค์ประกอบและลูกหลานของตนที่มีผลผูกพันจะเปิดใช้งาน

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

ko.applyBindings(myViewModel, document.getElementById('someElementId'))

สิ่งนี้ จำกัด การเปิดใช้งานองค์ประกอบที่มี ID someElementIdและผู้สืบทอด

ดูเอกสารประกอบสำหรับรายละเอียดเพิ่มเติม


72
หากคุณต้องการใช้ตัวเลือก jQuery คุณจะต้องเพิ่ม[0]เพื่อระบุองค์ประกอบ DOM จริง (แทนวัตถุ jQuery) เช่น:ko.applyBindings(myViewModel, $('#someElementId')[0])
MrBoJangles

3
นี่ควรเป็นคำตอบที่ยอมรับได้ คุณยังคงสามารถใช้วัตถุต้นแบบได้เช่นคำตอบที่ยอมรับในปัจจุบันและจากนั้นผูกแต่ละมุมมองรุ่นกับองค์ประกอบที่เหมาะสมในหน้า สิ่งนี้จะประหยัดประสิทธิภาพและ จำกัด ขอบเขตที่จำเป็นสำหรับการผูกข้อมูล
Kevin Heidt

เป็นไปได้ไหมที่จะสื่อสาร viewModels ด้วยวิธีนี้? เช่นฉันมี TaskVM และ NoteVM ภารกิจสามารถมี Notes ดังนั้น TaskVM ของฉันจะต้องมี observableArray คือโน้ตที่มีประเภทเป็น TaskVM คุณสามารถแบ่งปันตัวอย่างสำหรับกรณีเช่นนี้ได้หรือไม่?
ahmet

อาจเป็นการดีที่สุดที่จะถามเกี่ยวกับการสื่อสารระหว่าง VMs ในคำถามใหม่
Richard Nalezynski

21

นี่คือคำตอบของฉันหลังจากเสร็จสิ้นโครงการขนาดใหญ่ที่มี ViewModels จำนวนมากในมุมมองเดียว

มุมมอง Html

    <!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
    <div id="container1">
        <ul>
            <li >Container1 item</li>
            <!-- ko foreach: myItems -->
            <li>Item <span data-bind="text: $data"></span></li>
            <!-- /ko -->
        </ul>
    </div>

    <div id="container2">
        <ul>
            <li >Container2 item</li>
            <!-- ko foreach: myItems -->
                <li>Item <span data-bind="text: $data"></span></li>
            <!-- /ko -->
        </ul>
    </div>

    <script src="js/jquery-1.11.1.js"></script>
    <script src="js/knockout-3.0.0.js"></script>
    <script src="js/DataFunction.js"></script>
    <script src="js/Container1ViewModel.js"></script>
    <script src="js/Container2ViewModel.js"></script>

</body>
</html>

สำหรับมุมมองนี้ฉันกำลังสร้างแบบจำลอง 2 มุมมองสำหรับ id = container1 และ id = container2 ในไฟล์ javascript แยกต่างหากสองไฟล์

Container1ViewModel.js

function Container1ViewModel()
{
    var self = this;
    self.myItems = ko.observableArray();
    self.myItems.push("ABC");
    self.myItems.push("CDE");

} 

Container2ViewModel.js

function Container2ViewModel() {
    var self = this;
    self.myItems = ko.observableArray();
    self.myItems.push("XYZ");
    self.myItems.push("PQR");

}

จากนั้นหลังจาก 2 viewmodels เหล่านี้กำลังลงทะเบียนเป็น viewmodels แยกต่างหากใน DataFunction.js

var container1VM;
var container2VM;

$(document).ready(function() {

    if ($.isEmptyObject(container1VM)) {
        container1VM = new Container1ViewModel();
        ko.applyBindings(container1VM, document.getElementById("container1"));
    }

    if ($.isEmptyObject(container2VM)) {
        container2VM = new Container2ViewModel();
        ko.applyBindings(container2VM, document.getElementById("container2"));
    }
});

เช่นนี้คุณสามารถเพิ่มจำนวนมุมมองรุ่นใด ๆ ให้แยก divs แต่ให้แน่ใจว่าอย่าสร้างมุมมองแยกต่างหากสำหรับ div ภายใน div ที่ลงทะเบียน


เป็นไปได้ที่จะทำมันเป็นชนิดของ viewmodel ภายในของอื่น ๆ แทนที่จะเป็นองค์ประกอบที่แยกจากกันของ DOM หรือไม่?
UserEsp

4

ตรวจสอบปลั๊กอิน MultiModels สำหรับ Knockout JS - https://github.com/sergun/Knockout-MultiModels


6
สิ่งนี้มีประโยชน์อย่างไรมากกว่าเพียงแค่ ko.applyBindings (viewModel, document.getElementById ("divName")) มันไม่ใช่แค่น้ำตาลทรายหรือเปล่า
เปาโลเดลมุ

1
@Poloolo del Mundo นอกจากนี้ยังเพิ่มการพึ่งพาปลั๊กอิน LiveQuery
Lars Gyrup Brink Nielsen

@PaolodelMundo จุดประสงค์ของปลั๊กอินเพื่อให้สามารถใช้ชุดมุมมองในรูปแบบรูปลอกได้
Sergey Zwezdin

1

เราใช้ส่วนประกอบเพื่อให้บรรลุเป้าหมายนั้น ( http://knockoutjs.com/documentation/component-overview.html )

ตัวอย่างเช่นเรามีไลบรารีองค์ประกอบนี้ที่เรากำลังพัฒนา: https://github.com/EDMdesigner/knobjs

หากคุณขุดลงในรหัสคุณจะเห็นว่าตัวอย่างเช่นเราใช้ส่วนประกอบปุ่มลูกบิดในหลาย ๆ ที่

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