Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/backbone.js/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在backbone.js中创建向导进程_Backbone.js - Fatal编程技术网

在backbone.js中创建向导进程

在backbone.js中创建向导进程,backbone.js,Backbone.js,我是backbone.js新手,在设计“向导”类型的流程(也称为多步骤表单)时遇到了一些问题。该向导应该能够根据用户对问题的响应处理不同的屏幕分支逻辑,随着用户的进展存储对每个屏幕的响应,并最终能够将所有表单响应(每个步骤)序列化为一个大对象(可能是JSON)。向导问题每年都在变化,我需要能够同时支持多个存在的类似向导 我已经掌握了创建屏幕的基本知识(使用主干表单),但现在我想保存用户输入,我想不出最好的方法。我看到的大多数示例都有一种特定类型的对象(例如,Todo),您只需创建它们的集合(例如

我是backbone.js新手,在设计“向导”类型的流程(也称为多步骤表单)时遇到了一些问题。该向导应该能够根据用户对问题的响应处理不同的屏幕分支逻辑,随着用户的进展存储对每个屏幕的响应,并最终能够将所有表单响应(每个步骤)序列化为一个大对象(可能是JSON)。向导问题每年都在变化,我需要能够同时支持多个存在的类似向导

我已经掌握了创建屏幕的基本知识(使用主干表单),但现在我想保存用户输入,我想不出最好的方法。我看到的大多数示例都有一种特定类型的对象(例如,
Todo
),您只需创建它们的集合(例如,
TodoList
),但我有一个混合的主干。由于不同的屏幕类型,模型定义不尽相同,所以它看起来并不那么简单。有没有关于如何实例化向导及其包含的屏幕并记录用户响应的指针

如果有帮助的话,我可以发布一个JSFIDLE,其中包含我的视图代码,到目前为止,这些代码只会向前和向后显示屏幕(没有用户输入响应记录或屏幕分支)

编辑:根据请求,我希望看到一个向导的JSON返回值,该值已保存为如下所示(作为最终目标):


您需要做的一件大事是将工作流与视图本身分开。也就是说,您应该有一个对象来协调视图之间的工作流,保留在视图中输入的数据,并使用视图的结果(通过事件或其他方式)来确定下一步的方向

我在博客中更详细地介绍了这一点,这里有一个非常简单的向导式界面示例:

在这里:

以下是第一篇文章中的基本代码,其中显示了工作流对象及其如何协调视图:


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

我认为德里克的回答是可以接受的,因为它比我现有的更干净,但这不是一个解决方案,因为我有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!"
        }
    ]
});
当时,我们也有类似的需求,并建造了一座新的建筑


w、 r.t显式Q,在此向导中,所有内容都存储在localStorage中,可以作为类似于指定格式的对象进行访问。

Hello。你能解释一下你要拿什么吗?反应是什么样的?也许你可以举个例子?顺便说一句,这是一个很好的问题。您好,获取将用于检索用户以前保存的对向导问题的响应(这意味着我还必须有一个保存方法用于模型)。我很想给你一个例子,看看这个回复会是什么样子,但我似乎无法思考如何构造这个应用程序,从而给你这个答案。我需要一个更大的大脑@user1248256好的,多亏了你的问题,我对这个问题考虑得更多了,并对这个问题进行了编辑,以包含我最终希望保存的向导查询以JSON(大约)形式返回的内容。也许我必须创建一个新模型,或者修补主干网的一些同步或解析方法?+1,感谢您的回复。我读过这些博客文章,不幸的是,我认为这不适合我正在做的事情(假设我理解它)。我正在做的向导只是创建一个数据块,用于自动填充现有的非常大且结构不好的PDF文件,我与该文件紧密耦合,因此我无法将所有部分整理成漂亮的模型;实际上,拥有一组通用的“屏幕”更容易,因为我最终必须映射回PDF结构。很明显,要将这一点融入MVC式的结构很有挑战性。+1感谢你花在回答这个问题上的时间。。。来自一个上瘾的主干网用户:)您如何为这些视图设置来回逻辑?我很难理解如何使用“previous/next”逻辑扩展回调,而不需要大量冗余代码。

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
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!"
        }
    ]
});