2012-05-31 7 views
14

मैं backbone.js के लिए नया हूं और किसी समस्या के चारों ओर अपने सिर को लपेटने में कुछ परेशानी हो रही है, जिसमें मैं एक "जादूगर" प्रकार की प्रक्रिया (ए.के.ए. एक बहु-चरण फ़ॉर्म) तैयार कर रहा हूं। यह विज़ार्ड प्रश्नों के उपयोगकर्ता की प्रतिक्रिया के आधार पर विभिन्न स्क्रीन ब्रांचिंग तर्क को संभालने में सक्षम होना चाहिए, प्रत्येक स्क्रीन पर प्रतिक्रियाओं को उपयोगकर्ता की प्रगति के रूप में संग्रहीत करें, और अंत में सभी फॉर्म प्रतिक्रियाओं (प्रत्येक चरण) को एक बड़ी वस्तु में क्रमबद्ध करने में सक्षम होना चाहिए (शायद जेएसओएन)। विज़ार्ड प्रश्न साल-दर-साल बदल रहे होंगे, और मुझे एक ही समय में अस्तित्व में कई समान जादूगरों का समर्थन करने में सक्षम होना चाहिए।backbone.js में एक विज़ार्ड प्रक्रिया बनाना

मुझे स्क्रीन बनाने के लिए मूल बातें मिल गई हैं (रीढ़ की हड्डी-रूपों का उपयोग करके), लेकिन अब मैं उस बिंदु पर हूं जहां मैं उपयोगकर्ता इनपुट को सहेजना चाहता हूं और मैं सबसे अच्छा तरीका नहीं सोच सकता कर दो। मैंने देखा है कि अधिकांश उदाहरणों में एक विशिष्ट प्रकार का ऑब्जेक्ट है (उदाहरण के लिए Todo) और आप बस उनका संग्रह बनाते हैं (उदाहरण के लिए TodoList), लेकिन मुझे बैकबोन का मिश्रित बैग मिला है। विभिन्न स्क्रीन प्रकारों के कारण मॉडल परिभाषाएं यह काफी आसान प्रतीत नहीं होता है। किसी भी संकेतक कि मुझे अपने जादूगर और इसकी निहित स्क्रीन को तुरंत चालू करना चाहिए, और उपयोगकर्ता प्रतिक्रियाओं को रिकॉर्ड करना चाहिए?

अगर यह मेरी दृश्य कोड के साथ एक jsfiddle पोस्ट करने में मदद करता है जो अभी तक केवल आगे और पीछे की ओर स्क्रीन (कोई उपयोगकर्ता इनपुट प्रतिक्रिया रिकॉर्डिंग या स्क्रीन ब्रांचिंग) नहीं जाता है।

var Wizard = Backbone.Model.extend({ 

    initialize: function(options) { 
     this.set({ 
      pathTaken: [0] 
     }); 
    }, 

    currentScreenID: function() { 
     return _(this.get('pathTaken')).last(); 
    }, 

    currentScreen: function() { 
     return this.screens[this.currentScreenID()]; 
    }, 

    isFirstScreen: function(screen) { 
     return (_(this.screens).first() == this.currentScreen()); 
    }, 

    // This function should be overridden by wizards that have 
    // multiple possible "finish" screens (depending on path taken) 
    isLastScreen: function(screen) { 
     return (_(this.screens).last() == this.currentScreen()); 
    }, 

    // This function should be overridden by non-trivial wizards 
    // for complex path handling logic 
    nextScreen: function() { 
     // return immediately if on final screen 
     if (this.isLastScreen(this.currentScreen())) return; 
     // otherwise return the next screen in the list 
     this.get('pathTaken').push(this.currentScreenID() + 1); 
     return this.currentScreen(); 
    }, 

    prevScreen: function() { 
     // return immediately if on first screen 
     if (this.isFirstScreen(this.currentScreen())) return; 
     // otherwise return the previous screen in the list 
     prevScreenID = _(_(this.get('pathTaken')).pop()).last(); 
     return this.screens[prevScreenID]; 
    } 
}); 

var ChocolateWizard = Wizard.extend({ 
    nextScreen: function() { 
     //TODO: Implement this (calls super for now) 
     //  Should go from screen 0 to 1 OR 2, depending on user response 
     return Wizard.prototype.nextScreen.call(this); 
    }, 
    screens: [ 
     // 0 
     Backbone.Model.extend({ 
      title : "Chocolate quiz", 
      schema: { 
       name: 'Text', 
       likesChocolate: { 
        title: 'Do you like chocolate?', 
        type: 'Radio', 
        options: ['Yes', 'No'] 
       } 
      } 
     }), 
     // 1 
     Backbone.Model.extend({ 
      title : "I'm glad you like chocolate!", 
      schema: { 
       chocolateTypePreference: { 
        title: 'Which type do you prefer?', 
        type: 'Radio', 
        options: [ 'Milk chocolate', 'Dark chocolate' ] 
       } 
      } 
     }), 
     //2 
     Backbone.Model.extend({ 
      title : "So you don't like chocolate.", 
      schema: { 
       otherSweet: { 
        title: 'What type of sweet do you prefer then?', 
        type: 'Text' 
       } 
      } 
     }) 
    ] 
}); 

wizard = new ChocolateWizard(); 

// I'd like to do something like wizard.screens.fetch here to get 
// any saved responses, but wizard.screens is an array of model 
// *definitions*, and I need to be working with *instances* in 
// order to fetch 

संपादित करें:

wizardResponse = { 
    userID: 1, 
    wizardType: "Chocolate", 
    screenResponses: [ 
     { likesChocolate: "No"}, 
     {}, 
     { otherSweet: "Vanilla ice cream" } 
    ] 
} 
+0

हैलो। क्या आप समझा सकते हैं कि आप क्या हासिल करना चाहते हैं?प्रतिक्रिया कैसी दिखती है? शायद आप एक उदाहरण दे सकते हैं? बीटीडब्ल्यू, बहुत अच्छा सवाल है। – theotheo

+0

हाय वहाँ, प्राप्तकर्ता उपयोगकर्ता के पूर्व-सहेजे गए प्रतिक्रियाओं को विज़ार्ड प्रश्नों को पुनर्प्राप्त करने के लिए होगा (जिसका अर्थ है कि मुझे मॉडल के लिए एक सहेजने की विधि भी होनी चाहिए)। मैं आपको एक उदाहरण देना चाहूंगा कि प्रतिक्रिया कैसी दिखाई देगी, लेकिन मुझे लगता है कि इस ऐप को आपको यह देने के लिए पर्याप्त रूप से कैसे संरचना करना है, इस बारे में सोचना नहीं लगता। मुझे एक बड़ा मस्तिष्क चाहिए! –

+0

@ user1248256 ठीक है, आपके प्रश्न के लिए धन्यवाद मैंने इस बारे में कुछ और सोचा है और जेएसओएन (लगभग) में लौटने के लिए अंत में एक सहेजी गई विज़ार्ड क्वेरी को शामिल करने के लिए प्रश्न संपादित किया है। शायद मुझे बैकबोन की सिंक या पार्स विधियों में से कुछ नया मॉडल बनाना होगा या पैच करना होगा? –

उत्तर

14

बड़ी बात: जब अनुरोध किया है, मैं एक जादूगर है कि कुछ इस तरह देखने के लिए (एक अंत लक्ष्य के रूप में) सहेज लिया गया है के लिए एक JSON वापसी मान देखना चाहेंगे आपको वर्कफ़्लो को स्वयं विचारों से अलग करना है। यही है, आपके पास एक ऑब्जेक्ट होना चाहिए जो विचारों के बीच कार्य प्रवाह को समन्वयित करता है, जो विचारों में दर्ज किए गए डेटा पर रखता है, और विचारों के परिणामों का उपयोग करता है (घटनाओं या अन्य माध्यमों के माध्यम से) यह पता लगाने के लिए कि कहां जाना है आगामी।

मैं एक जादूगर शैली इंटरफेस की एक बहुत ही सरल उदाहरण है, यहाँ के साथ, और अधिक विस्तार में इस बारे में भी ब्लॉग है:

http://lostechies.com/derickbailey/2012/05/10/modeling-explicit-workflow-with-code-in-javascript-and-backbone-apps/

और यहाँ:

http://lostechies.com/derickbailey/2012/05/15/workflow-in-backbone-apps-triggering-view-events-from-dom-events/

यहाँ उस प्रथम पोस्ट का मूल कोड, जो वर्कफ़्लो ऑब्जेक्ट दिखाता है और यह दृश्यों का समन्वय कैसे करता है:


orgChart = { 

    addNewEmployee: function(){ 
    var that = this; 

    var employeeDetail = this.getEmployeeDetail(); 
    employeeDetail.on("complete", function(employee){ 

     var managerSelector = that.selectManager(employee); 
     managerSelector.on("save", function(employee){ 
     employee.save(); 
     }); 

    }); 
    }, 

    getEmployeeDetail: function(){ 
    var form = new EmployeeDetailForm(); 
    form.render(); 
    $("#wizard").html(form.el); 
    return form; 
    }, 

    selectManager: function(employee){ 
    var form = new SelectManagerForm({ 
     model: employee 
    }); 
    form.render(); 
    $("#wizard").html(form.el); 
    return form; 
    } 
} 

// implementation details for EmployeeDetailForm go here 

// implementation details for SelectManagerForm go here 

// implementation details for Employee model go here 
+0

+1, प्रतिक्रिया के लिए धन्यवाद। मैंने ब्लॉग पोस्ट पढ़े हैं और दुर्भाग्य से मुझे नहीं लगता कि यह मेरे लिए क्या अच्छा है (मान लीजिए कि मैं इसे समझता हूं) के लिए एक अच्छा फिट होगा। जो विज़ार्ड मैं कर रहा हूं वह केवल डेटा का एक ब्लॉब बनाने के लिए मौजूद है जिसका उपयोग मौजूदा बहुत बड़ी और अच्छी तरह से संरचित पीडीएफ फाइल को भरने के लिए किया जाएगा, जिसे मैं कसकर जोड़ता हूं, इसलिए मैं नहीं कर सकता अच्छे टुकड़ों में सभी टुकड़ों को चिढ़ाओ; जेनेरिक "स्क्रीन" की एक सरणी रखना वास्तव में आसान है क्योंकि मुझे पीडीएफ संरचना में वापस मैपिंग समाप्त करना है। निश्चित रूप से इसे एक एमवीसी जैसी संरचना में फिट करने के लिए चुनौतीपूर्ण लग रहा है। –

+0

+1 उस समय के लिए +1 जब आप जवाब देने में बिताए थे ... एक आदी रीढ़ की हड्डी उपयोगकर्ता से :) –

+0

आप उन विचारों के लिए आगे और आगे तर्क कैसे लगाएंगे? मुझे बहुत सारे अनावश्यक कोड के बिना "पिछले/अगले" तर्क के साथ कॉलबैक बढ़ाने के लिए समझने में समस्याएं हैं। – Gambo

5

मैं डेरिक के जवाब को स्वीकार कर रहा हूं क्योंकि यह मेरे पास जितना साफ है, उतना ही स्वीकार्य है, लेकिन यह एक समाधान नहीं है जिसका उपयोग मैं अपने मामले में कर सकता हूं क्योंकि मेरे पास सौदा करने के लिए 50+ स्क्रीन हैं, मैं अच्छे मॉडल में नहीं तोड़ सकता - मुझे उनकी सामग्री दी गई है और उन्हें बस दोहराना है।

यहां हैकी मॉडल कोड है जो मैं आया हूं जिसके साथ स्क्रीन स्विचिंग तर्क हैंडल करता है। मुझे यकीन है कि मैं इसे और अधिक रिफैक्टर कर दूंगा क्योंकि मैं इस पर काम करना जारी रखता हूं।

var Wizard = Backbone.Model.extend({ 

    initialize: function(options) { 
     this.set({ 
      pathTaken: [0], 
      // instantiate the screen definitions as screenResponses 
      screenResponses: _(this.screens).map(function(s){ return new s; }) 
     }); 
    }, 

    currentScreenID: function() { 
     return _(this.get('pathTaken')).last(); 
    }, 

    currentScreen: function() { 
     return this.screens[this.currentScreenID()]; 
    }, 

    isFirstScreen: function(screen) { 
     screen = screen || this.currentScreen(); 
     return (_(this.screens).first() === screen); 
    }, 

    // This function should be overridden by wizards that have 
    // multiple possible "finish" screens (depending on path taken) 
    isLastScreen: function(screen) { 
     screen = screen || this.currentScreen(); 
     return (_(this.screens).last() === screen); 
    }, 

    // This function should be overridden by non-trivial wizards 
    // for complex path handling logic 
    nextScreenID: function(currentScreenID, currentScreen) { 
     // default behavior is to return the next screen ID in the list 
     return currentScreenID + 1; 
    }, 

    nextScreen: function() { 
     // return immediately if on final screen 
     if (this.isLastScreen()) return; 
     // otherwise get next screen id from nextScreenID function 
     nsid = this.nextScreenID(this.currentScreenID(), this.currentScreen()); 
     if (nsid) { 
      this.get('pathTaken').push(nsid); 
      return nsid; 
     } 
    }, 

    prevScreen: function() { 
     // return immediately if on first screen 
     if (this.isFirstScreen()) return; 
     // otherwise return the previous screen in the list 
     prevScreenID = _(_(this.get('pathTaken')).pop()).last(); 
     return this.screens[prevScreenID]; 
    } 

}); 

var ChocolateWizard = Wizard.extend({ 

    initialize: function(options) { 
     Wizard.prototype.initialize.call(this); // super() 

     this.set({ 
      wizardType: 'Chocolate', 
     }); 
    }, 

    nextScreenID: function(csid, cs) { 
     var resp = this.screenResponses(csid); 
     this.nextScreenController.setState(csid.toString()); // have to manually change states 
     if (resp.nextScreenID) 
      // if screen defines a custom nextScreenID method, use it 
      return resp.nextScreenID(resp, this.get('screenResponses')); 
     else 
      // otherwise return next screen number by default 
      return csid + 1; 
    }, 

    // convenience function 
    screenResponses: function(i) { 
     return this.get('screenResponses')[i]; 
    }, 

    screens: [ 
     // 0 
     Backbone.Model.extend({ 
      title : "Chocolate quiz", 
      schema: { 
       name: 'Text', 
       likesChocolate: { 
        title: 'Do you like chocolate?', 
        type: 'Radio', 
        options: ['Yes', 'No'] 
       } 
      }, 
      nextScreenID: function(thisResp, allResp) { 
       if (thisResp.get('likesChocolate') === 'Yes') 
        return 1; 
       else 
        return 2; 
      } 
     }), 
     // 1 
     Backbone.Model.extend({ 
      title : "I'm glad you like chocolate!", 
      schema: { 
       chocolateTypePreference: { 
        title: 'Which type do you prefer?', 
        type: 'Radio', 
        options: [ 'Milk chocolate', 'Dark chocolate' ] 
       } 
      }, 
      nextScreenID: function(thisResp, allResp) { 
       return 3; // skip screen 2 
      } 
     }), 
     // 2 
     Backbone.Model.extend({ 
      title : "So you don't like chocolate.", 
      schema: { 
       otherSweet: { 
        title: 'What type of sweet do you prefer then?', 
        type: 'Text' 
       } 
      } 
     }), 
     // 3 
     Backbone.Model.extend({ 
      title : "Finished - thanks for taking the quiz!" 
     } 
    ] 
}); 
0

CloudMunch में, हम एक ऐसी ही जरूरत थी और Marionette-Wizard का निर्माण किया।

w.r.t स्पष्ट प्रश्न, इस विज़ार्ड में सभी सामग्री को स्थानीय स्टोरेज में संग्रहीत किया जाता है और आपके द्वारा निर्दिष्ट प्रारूप के समान ऑब्जेक्ट के रूप में एक्सेस किया जा सकता है।

संबंधित मुद्दे