2011-09-21 28 views
24

का उपयोग कर नॉकआउट मानचित्रण प्लगइन (http://knockoutjs.com/documentation/plugins-mapping.html) का उपयोग करके आप एक गहरा hierachical वस्तु मैप कर सकते हैं कस्टम वर्गों के लिए वस्तुओं?मानचित्रण गहरा श्रेणीबद्ध नॉकआउट मानचित्रण प्लगइन

अगर मैं कई स्तरों के साथ एक वस्तु है:

var data = { 
    name: 'Graham', 
    children: [ 
     { 
      name: 'Son of Graham', 
      children: [ 
       { 
        name: 'Son of Son of Graham', 
        children: [ 
         { 
          ... and on and on.... 
         } 
        ] 

       } 
      ] 
     } 
    ] 
} 

मैं कैसे जावास्क्रिप्ट में अपने कस्टम वर्गों के लिए यह नक्शा है:

var mapping = { 
    !! your genius solution goes here !! 

    !! need to create a myCustomPerson object for Graham which has a child myCustomerPerson object 
    !! containing "Son of Graham" and that child object contains a child myCustomerPerson 
    !! object containing "Son of Son of Graham" and on and on.... 

} 

var grahamModel = ko.mapping.fromJS(data, mapping); 

function myCustomPerson(name, children) 
{ 
    this.Name = ko.observable(name); 
    this.Children = ko.observableArray(children); 
} 

मानचित्रण प्लगइन रिकर्सिवली एक में इस डेटा को मैप कर सकते हैं मेरी कस्टम वस्तुओं का पदानुक्रम?

उत्तर

17

कुछ इस तरह (Live copy on js fiddle):

सीएसएस:

.left { 
    float: left; 
} 

.clear { 
    clear: both; 
}​ 

HTML:

<p>Current:&nbsp; 
    <a href="#" data-bind="visible: (stack.length > 0), text: selectedNode().name, click: selectParentNode"></a> 
    <span data-bind="visible: (stack.length <= 0), text: selectedNode().name"></span> 
</p> 
<p class="left">Children:&nbsp;</p> 
<ul class="left" data-bind="template: {name: 'childList', foreach: selectedNode().children}"></ul> 

<script type="text/html" id="childList"> 
    <li data-bind="click: function(){nodeViewModel.selectChildNode($data)}"> 
     <a href="#">A${name}</a> 
    </li> 
</script> 

<br /><br /> 
<ul class="clear" data-bind="template: {name: 'backBtn'}"></ul> 

<script type="text/html" id="backBtn"> 
    <a href="#" data-bind="visible: $data.selectedNode().back, click: function() { nodeViewModel.selectBackNode($data.selectedNode().back) }">Back</a> 
</script>​ 

जावास्क्रिप्ट:

var node = function(config, parent) { 
    this.parent = parent; 
    var _this = this; 

    var mappingOptions = { 
     children: { 
      create: function(args) { 
       return new node(args.data, _this); 
      } 
     } 
    }; 

    ko.mapping.fromJS(config, mappingOptions, this); 
}; 

var myModel = { 
    node: { 
     name: "Root", 
     children: [ 
      { 
      name: "Child 1", 
      back: 1, 
      children: [ 
       { 
       name: "Child 1_1", 
       back: 1, 
       children: [ 
        { 
        name: "Child 1_1_1", 
        back: 4, 
        children: [ 
         ]}, 
       { 
        name: "Child 1_1_2", 
        back: 2, 
        children: [ 
         ]}, 
       { 
        name: "Child 1_1_3", 
        back: 1, 
        children: [ 
         ]} 
        ]} 
      ]}, 
     { 
      name: "Child 2", 
      back: 1, 
      children: [ 
       { 
       name: "Child 2_1", 
       back: 1, 
       children: [ 
        ]}, 
      { 
       name: "Child 2_2", 
       back: 1, 
       children: [ 
        ]} 
      ]} 
     ] 
    } 
}; 

var viewModel = { 

    nodeData: new node(myModel.node, undefined), 

    selectedNode: ko.observable(myModel.node), 

    stack: [], 

    selectBackNode: function(numBack) { 

     if (this.stack.length >= numBack) { 
      for (var i = 0; i < numBack - 1; i++) { 
       this.stack.pop(); 
      } 
     } 
     else { 
      for (var i = 0; i < this.stack.length; i++) { 
       this.stack.pop(); 
      } 
     } 

     this.selectNode(this.stack.pop()); 
    }, 

    selectParentNode: function() { 
     if (this.stack.length > 0) { 
      this.selectNode(this.stack.pop()); 
     } 
    }, 

    selectChildNode: function(node) { 
     this.stack.push(this.selectedNode()); 
     this.selectNode(node); 
    }, 

    selectNode: function(node) { 
     this.selectedNode(node); 
    } 

}; 

window.nodeViewModel = viewModel; 
ko.applyBindings(viewModel);​ 

यह नमूना सिर्फ एक असीम नक्शे JSON डेटा का नेस्टेड सेट, और मैं वास्तव में एप्लिकेशन में इस सटीक कोड का उपयोग करके कह सकता हूं जो कि बहुत अच्छा काम करता है।

तरह

selectBackNode और selectParentNode अतिरिक्त कार्यों में से कुछ

तुम वापस पेड़ पर स्थानांतरित करने के लिए अनुमति देते हैं।

उदाहरण को नेविगेट करते समय अभिभावक लेबल एक स्तर तक जाने की अनुमति देने के लिए एक लिंक बन जाता है, और कुछ पत्ते नोड्स में एक बैक बटन होता है जो उन्हें किसी दिए गए स्तर से पेड़ को वापस ले जाने की अनुमति देता है।

--EDIT--

अपने पत्र-गांठ एक बच्चों सरणी आप एक समस्या है, जहां अतिरिक्त डेटा शुरू की है कि मॉडल में मौजूद नहीं है मिल सकता है नहीं है, तो।

+0

यह शानदार काम, HJ05 है। जवाब के लिए धन्यवाद। –

+0

स्टैक adt – booyaa

+0

के उपयोग के लिए +1 jsFiddle जैसे लिंक एक अच्छा * adjunct * हैं, लेकिन हमेशा उत्तर में प्रासंगिक कोड और मार्कअप ** डाल दें **। क्यों: http://meta.stackexchange.com/questions/118392/add-stack-overfow-faq-entry-or-similar-for-putting-code-in-the-question मैंने इसे आपके लिए किया है इस अवसर। –

4

मेरे अनुभव से, मैं कहूँगा कि यह किसी भी समस्या नहीं होनी चाहिए।

मैं निम्नलिखित लाइन का प्रयोग करेंगे -

var grahamModel = ko.mapping.fromJS(data); 

फिर अपने डीबगर (क्रोम या एफएफ + Firebug सबसे अच्छा काम करता है) में उत्पन्न वस्तु को देखने पर अगली पंक्ति पर एक ब्रेकपाइंट निर्धारित किया है। इस तरह आपको पता चलेगा कि ko.mapping एक व्यूमोडेल उत्पन्न करेगा जो आपकी आवश्यकताओं को पूरा करता है।

आम तौर पर, यह एक वस्तु जहां केवल अंत अंक (मूल्यों के साथ चर) ko.observables हैं उत्पन्न करता है। अन्य डेटा बार है कि आप ... children: [... की तरह डेटा के माध्यम से नेविगेशन के लिए उपयोग कर सकते हैं, के किसी भी साधारण JavaScript ऑब्जेक्ट के रूप में दिखाया जाता है।

1

यदि आप नेस्टेड मैपिंगऑप्शन (प्रत्येक नोड स्तर के लिए को मैप ऑब्जेक्ट बनाना) नहीं चाहते हैं, तो आप इस तथ्य का लाभ उठा सकते हैं कि बनाने के लिए को मैपिंग विकल्प आपको मूल ऑब्जेक्ट तक पहुंच प्रदान करते हैं।इस तरह कुछ:

function Folder(parent,data) { 
    var self = this; 
    self.parent = parent; 
    ko.mapping.fromJS(data, self.map, self); 
} 

Folder.prototype.map = { 
    'folders': { 
     create: function(options) { 
      var folder = new Folder(options.parent,options.data); 
      return folder; 
     } 
    } 
} 

var data = { name:"root", folders: [ {name:"child", folders: [] } ] }; 
var root = new Folder(null, data); 

इस तरह आपके पास केवल अपने क्लास प्रोटोटाइप (या कोई फ़ंक्शन हो सकता है) में मानचित्र की 1 प्रति है। आप Folder.parent साथ ही एक नमूदार होना चाहते हैं, तो आप नक्शे समारोह अंदर data.parent = parent; कर सकता है और अपने फ़ोल्डर निर्माता के लिए एक पैरामीटर के रूप में नहीं गुजरती हैं, या कि अंदर self.parent = parent;

+0

यह काम करता है। मैंने इसे नीचे दिए गए मेरे उत्तर के लिए इस्तेमाल किया। –

0

के बजाय फ़ोल्डर निर्माता मैं दृष्टिकोण का इस्तेमाल किया करते चेकबॉक्सों का पदानुक्रम बनाने के लिए इस answer में जहां बच्चों के साथ नोड्स ढहने योग्य होते हैं और जब आप माता-पिता को चेक/अनचेक करते हैं तो इसके वंशजों को चेक/अनचेक किया जाता है।

देखें मॉडल

var Category = function(data, parent) { 
    var self = this; 
    self.name = data.name; 
    self.id = data.id; 
    self.parent = parent; 
    self.categoryChecked = ko.observable(false); 
    ko.mapping.fromJS(data, self.map, self); 
}; 

// This will add a "map" to our category view model 
Category.prototype.map = { 
    'sub_categories' : { 
     create: function(options){ 
      var category = new Category(options.data, options.parent); 
      category.parent.categoryChecked.subscribe(function(value){ 
       category.categoryChecked(value); 
      }); 
      return category; 
     } 
    } 
}; 

एचटीएमएल (दृश्य)

<div data-role="panel" id="left-panel" data-position="left" data-position-fixed="false" data-theme="b"> 
      <div data-role="collapsible-set" data-bind="template: {name: 'category_collapsible', foreach: sub_categories}" data-mini="true" id="categories" data-iscroll> </div> 
     </div><!-- END left panel --> 

     <script type="text/html" id="category_collapsible"> 
      <div class="category_collapsible" data-mini="true" data-content-theme="b" data-inset="true" data-iconpos="right"> 
       <h3>  
        <input data-role="none" data-them="b" data-bind='checked: categoryChecked, jqmChecked: true, attr: {id: "category_checkbox_"+id}' class="chk_category" type="checkbox" /> 
        <label data-bind='attr: {for: "category_checkbox_"+id}'><span data-bind="text: name"> </span></label> 
       </h3> 
       <ul data-role="listview" data-bind="template: {name: 'category_list', foreach: sub_categories}"> 

       </ul> 
      </div> 
     </script><!-- END category_collapsible template --> 

     <script type="text/html" id="category_list"> 
      <!-- ko if: sub_categories().length==0 --> 
       <li data-theme="c"> 
        <input data-role="none" data-theme="c" data-bind='checked: categoryChecked, jqmChecked: true, attr: {id: "category_checkbox_"+id}' class="chk_category" type="checkbox"/> 
        <label data-corners="false" data-bind='attr: {for: "category_checkbox_"+id}'> 
         <span data-bind="text: name"> </span> 
        </label>   
       </li> 
      <!-- /ko --> 
      <!-- ko if: sub_categories().length>0 --> 
       <li data-theme="c" data-bind="template: {name: 'category_collapsible', data: $data}"></li> 
      <!-- /ko --> 
     </script> 
संबंधित मुद्दे