Sencha Touch 1.xx - 从服务器代理加载关联模型

发布于 2025-01-07 21:39:27 字数 4836 浏览 0 评论 0原文

我一直试图从关联的模型存储中检索数据。请允许我简要概述一下我想要实现的目标。

我需要一个测验列表,点击测验后,它将显示一个问题列表。点击问题后,您将获得相关的多项选择答案(可能是带有按钮的数据视图或另一个列表)。

在早期的测试版中,我使用扁平树存储来显示测验,但这在美观方面受到限制,并且不允许我轻松地将数据与 API 同步,因此我试图让相关模型正常工作。我在网上发现了类似的问题,但不能完全得到我想要的东西。

这是相关代码(在 MVC 设置中)。我有 3 个关联的模型:

QuizModel.js:

app.models.QuizModel = Ext.regModel("QuizModel", {
    fields: [
        { name: 'id', type: 'int' },
        { name: 'studentid', type: 'int' },
        { name: 'dateAllocated', type: 'string' },
        { name: 'category', type: 'string' },
    ],

    associations: [
        {type: 'hasMany', model: 'QuestionModel', name: 'questions'},
    ],

    proxy: {
        type: 'rest',
        actionMethods: {create: "POST", read: "POST", update: "PUT", destroy: "DELETE"},
        url: 'http://localhost/bm/core/api/quiz',
        reader: {
            type: 'json',
            root: 'quizes'
        }
    }

});

app.stores.QuizStore = new Ext.data.Store({
    model: "QuizModel",
    storeId: 'quizStore'
});

QuestionModel.js:

app.models.QuestionModel = Ext.regModel("QuestionModel", {
    fields: [
        { name: 'id', type: 'int' },
        { name: 'quizmodel_id', type: 'int'},
        { name: 'prompt', type: 'string' },
        { name: 'level', type: 'int' },
        { name: 'categoty', type: 'string' }
    ],
    associations: [
        {type: 'hasMany', model: 'AnswerModel', name: 'answers'},
        {type: 'belongsTo', model: 'QuizModel'}
    ]

});

AnswerModel.js:

app.models.AnswerModel = Ext.regModel("AnswerModel", {
    fields: [
        { name: 'id', type: 'int' },
        { name: 'questionmodel_id', type: 'int' },
        { name: 'prompt', type: 'string' },
        { name: 'correct', type: 'string' }
    ],
    associations: [
        {type: 'belongsTo', model: 'QuestionModel'}
    ]
});

QuizController.js:

app.controllers.QuizController = new Ext.Controller({
    index: function(options) {
        console.log('home');
    },
    quizTap: function(options){
        var currentQuiz = app.stores.QuizStore.getAt(options.index);
        var questions = currentQuiz.questions().load().getAt(0);

        app.views.questionList.updateWithRecord(questions);
        app.views.viewport.setActiveItem(
            app.views.questionList, options.animation
        );
    }
});

最后,我的其余 API 响应如下所示:

{
    "status" : true,
    "quizes" : [{ 
            "id" : "1",
            "category" : "Privacy",
            "date_allocated" : "1329363878",
            "questions" : [{ 
                    "id" : "1",
                    "prompt" : "Lorem ipsum dolor sit amet?",
                    "answers" : [{
                            "id" : "1",
                            "correct" : "1",
                            "prompt" : "yes"
                    },
                    { 
                            "id" : "2",
                            "correct" : "0",
                            "prompt" : "no"
                    }]
            }]
     }]
}

这会导致:

“未捕获错误:您正在使用 ServerProxy,但尚未为其提供 URL。”。

现在,我的 QuizModel 具有与 REST API 通信所需的代理,但从 questions() 加载似乎使用默认代理。我尝试使用所需的参数(包括 url 和必要的 api 密钥)配置加载调用,但这似乎不起作用。我似乎找不到任何关于如何执行此操作的文档,并且大多数相关帖子仅讨论本地存储。请帮忙!

编辑:添加我的问题列表视图:

BuddeMobile.views.QuestionList = Ext.extend(Ext.Panel, {
    title: 'Quiz',
    iconCls: 'quiz',
    cls: 'question',
    scroll: 'vertical',

    initComponent: function(){
        Ext.apply(this, {
            dockedItems: [{
                xtype: 'toolbar',
                title: 'Quiz'
            }],
            items:  [{
                xtype: 'list',
                itemTpl: '<div class="quiz-question">{prompt}</div>',
                store: 'quizStore',
                listeners: {
                    itemtap:  function (list, index, el, e){
                        console.log('question tap',el);
                    }
                }
            }]
        });

        BuddeMobile.views.QuestionList.superclass.initComponent.call(this, arguments);
    },
    updateWithRecord: function(record) {
        var toolbar = this.getDockedItems()[0];
        toolbar.setTitle(record.get('category')); //works

        var list = this.items.get(0);
        console.log(record.questions()); //prints out mixed collection of questions
        var question1 = record.questions().getAt(0); //testing
        console.log(question1.answers()); //prints out mixed collection for first question's answers
        list.update(record.questions()); //does not work. How can I populate the list??
    }


});

如您所见,我可以获得所需的数据(当我在登录时加载商店时),但我不知道如何使列表使用数据子集。我已经尝试过更新功能,但这并没有起到多大作用!

I'm stuck trying to retrieve data from an associated model store. Allow me to give a brief overview of what I am trying to achieve.

I need a List of quizes, and upon tapping on a quiz it will show a List of questions. Upon tapping on a question you will then get the associated multiple choice answers (maybe a dataview with buttons or another List).

In an earlier beta I used a flat tree store to display the quiz but that was limiting in aesthetics and didn't allow me to sync my data with the api very easily, and thus I am trying to get the associated models working instead. I've found similar issues online can't quite get what I am after.

Here's the relevant code (in MVC setup). I have 3 associated models:

QuizModel.js:

app.models.QuizModel = Ext.regModel("QuizModel", {
    fields: [
        { name: 'id', type: 'int' },
        { name: 'studentid', type: 'int' },
        { name: 'dateAllocated', type: 'string' },
        { name: 'category', type: 'string' },
    ],

    associations: [
        {type: 'hasMany', model: 'QuestionModel', name: 'questions'},
    ],

    proxy: {
        type: 'rest',
        actionMethods: {create: "POST", read: "POST", update: "PUT", destroy: "DELETE"},
        url: 'http://localhost/bm/core/api/quiz',
        reader: {
            type: 'json',
            root: 'quizes'
        }
    }

});

app.stores.QuizStore = new Ext.data.Store({
    model: "QuizModel",
    storeId: 'quizStore'
});

QuestionModel.js:

app.models.QuestionModel = Ext.regModel("QuestionModel", {
    fields: [
        { name: 'id', type: 'int' },
        { name: 'quizmodel_id', type: 'int'},
        { name: 'prompt', type: 'string' },
        { name: 'level', type: 'int' },
        { name: 'categoty', type: 'string' }
    ],
    associations: [
        {type: 'hasMany', model: 'AnswerModel', name: 'answers'},
        {type: 'belongsTo', model: 'QuizModel'}
    ]

});

AnswerModel.js:

app.models.AnswerModel = Ext.regModel("AnswerModel", {
    fields: [
        { name: 'id', type: 'int' },
        { name: 'questionmodel_id', type: 'int' },
        { name: 'prompt', type: 'string' },
        { name: 'correct', type: 'string' }
    ],
    associations: [
        {type: 'belongsTo', model: 'QuestionModel'}
    ]
});

QuizController.js:

app.controllers.QuizController = new Ext.Controller({
    index: function(options) {
        console.log('home');
    },
    quizTap: function(options){
        var currentQuiz = app.stores.QuizStore.getAt(options.index);
        var questions = currentQuiz.questions().load().getAt(0);

        app.views.questionList.updateWithRecord(questions);
        app.views.viewport.setActiveItem(
            app.views.questionList, options.animation
        );
    }
});

and finally, my rest API response looks something like this:

{
    "status" : true,
    "quizes" : [{ 
            "id" : "1",
            "category" : "Privacy",
            "date_allocated" : "1329363878",
            "questions" : [{ 
                    "id" : "1",
                    "prompt" : "Lorem ipsum dolor sit amet?",
                    "answers" : [{
                            "id" : "1",
                            "correct" : "1",
                            "prompt" : "yes"
                    },
                    { 
                            "id" : "2",
                            "correct" : "0",
                            "prompt" : "no"
                    }]
            }]
     }]
}

This results in:

"Uncaught Error: You are using a ServerProxy but have not supplied it with a url.".

Now my QuizModel has the required proxy to communicate to my REST API, but loading from questions() seems to use a default proxy. I've tried configuring the load call with the required parameters (including url and necessary api key) but this doesn't appear to work. I can't seem to find any documentation on how I should be doing this, and most related posts talk about localstorage only. Please help!

edit: adding my question list view:

BuddeMobile.views.QuestionList = Ext.extend(Ext.Panel, {
    title: 'Quiz',
    iconCls: 'quiz',
    cls: 'question',
    scroll: 'vertical',

    initComponent: function(){
        Ext.apply(this, {
            dockedItems: [{
                xtype: 'toolbar',
                title: 'Quiz'
            }],
            items:  [{
                xtype: 'list',
                itemTpl: '<div class="quiz-question">{prompt}</div>',
                store: 'quizStore',
                listeners: {
                    itemtap:  function (list, index, el, e){
                        console.log('question tap',el);
                    }
                }
            }]
        });

        BuddeMobile.views.QuestionList.superclass.initComponent.call(this, arguments);
    },
    updateWithRecord: function(record) {
        var toolbar = this.getDockedItems()[0];
        toolbar.setTitle(record.get('category')); //works

        var list = this.items.get(0);
        console.log(record.questions()); //prints out mixed collection of questions
        var question1 = record.questions().getAt(0); //testing
        console.log(question1.answers()); //prints out mixed collection for first question's answers
        list.update(record.questions()); //does not work. How can I populate the list??
    }


});

As you can see I can get the data I need (as I load the store upon login), but I don't know how to make the list use the subset of data. I have tried the update function, but this isn't doing a lot!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

绝對不後悔。 2025-01-14 21:39:27

现在,我通过使用单独的存储而不是尝试让单个嵌套存储来完成所有操作,可以正确运行我的测验。为此,我必须确保我的服务器处理 JSON 模型并相应设置外键。我的模型和例子商店:

app.models.Quiz = Ext.regModel("Quiz", {
    fields: [
        { name: 'id', type: 'int' },
        { name: 'studentid', type: 'int' },
        { name: 'dateAllocated', type: 'string' },
        { name: 'category', type: 'string' },
    ],

    associations: [
    {type: 'hasMany', model: 'Question', name: 'questions'},
],

    proxy: {
        type: 'rest',
        actionMethods: {create: "POST", read: "POST", update: "PUT", destroy: "DELETE"},
        url: 'http://localhost/bm/core/api/quiz',
        reader: {
            type: 'json',
            root: 'quizes',
            id: 'id'
        }
    }

});

app.stores.QuizStore = new Ext.data.Store({
    model: "Quiz",
    storeId: 'quizStore'
});

和问题模型,请注意 quiz_id 字段:

app.models.Question = Ext.regModel("Question", {
    fields: [
        { name: 'id', type: 'int' },
        { name: 'quiz_id', type: 'int'},
        { name: 'prompt', type: 'string' },
        { name: 'level', type: 'int' },
        { name: 'category', type: 'string' }
    ],
    associations: [
        {type: 'hasMany', model: 'Answer', name: 'answers'},
        {type: 'belongsTo', model: 'Quiz'}
    ],

    proxy: {
        type: 'rest',
        actionMethods: {create: "POST", read: "POST", update: "PUT", destroy: "DELETE"},
        url: 'http://localhost/bm/core/api/questions',
        reader: {
            type: 'json',
            root: 'questions',
            id: 'id'
        }
    }   
});

app.stores.QuestionStore = new Ext.data.Store({
    model: "Question",
    storeId: 'questionStore'
});

此设置允许我为每个商店(列表)拥有单独的视图,可以根据选择进行过滤。请注意,我的 API 仅为登录用户加载测验/问题/答案,因此登录时加载的内容不会太多。

从控制器过滤特定列表的商店的示例:

showQuiz: function(options){
    //id passed from List's itemTap event
        var currentQuiz = app.stores.QuizStore.getById(options.id);

        app.stores.QuestionStore.clearFilter();
        //filter questions by selected quiz
        app.stores.QuestionStore.filter({
            property: 'quiz_id',
            value: options.id,
            exactMatch: true
        });

        //pass quiz record for setting toolbar title etc
        app.views.questionList.updateWithRecord(currentQuiz);

        app.views.quiz.setActiveItem(
            app.views.questionList, options.animation
        );

    }

希望这可以帮助任何遇到同样问题的人!

I now have my quiz functioning correctly by using separate stores instead of trying to get the single nested store to do everything. To do this I had to make sure my server dealt out JSON models with foreign keys set accordingly. Example of my models & stores:

app.models.Quiz = Ext.regModel("Quiz", {
    fields: [
        { name: 'id', type: 'int' },
        { name: 'studentid', type: 'int' },
        { name: 'dateAllocated', type: 'string' },
        { name: 'category', type: 'string' },
    ],

    associations: [
    {type: 'hasMany', model: 'Question', name: 'questions'},
],

    proxy: {
        type: 'rest',
        actionMethods: {create: "POST", read: "POST", update: "PUT", destroy: "DELETE"},
        url: 'http://localhost/bm/core/api/quiz',
        reader: {
            type: 'json',
            root: 'quizes',
            id: 'id'
        }
    }

});

app.stores.QuizStore = new Ext.data.Store({
    model: "Quiz",
    storeId: 'quizStore'
});

and the question model, note the field for quiz_id:

app.models.Question = Ext.regModel("Question", {
    fields: [
        { name: 'id', type: 'int' },
        { name: 'quiz_id', type: 'int'},
        { name: 'prompt', type: 'string' },
        { name: 'level', type: 'int' },
        { name: 'category', type: 'string' }
    ],
    associations: [
        {type: 'hasMany', model: 'Answer', name: 'answers'},
        {type: 'belongsTo', model: 'Quiz'}
    ],

    proxy: {
        type: 'rest',
        actionMethods: {create: "POST", read: "POST", update: "PUT", destroy: "DELETE"},
        url: 'http://localhost/bm/core/api/questions',
        reader: {
            type: 'json',
            root: 'questions',
            id: 'id'
        }
    }   
});

app.stores.QuestionStore = new Ext.data.Store({
    model: "Question",
    storeId: 'questionStore'
});

This setup allowed me to have separate views for each store (Lists) that can be filtered depending on selection. Note that my API loads quizes/questions/answers only for the logged in user, so it's not too much to load on login.

Example of filtering a store for a particular list from a controller:

showQuiz: function(options){
    //id passed from List's itemTap event
        var currentQuiz = app.stores.QuizStore.getById(options.id);

        app.stores.QuestionStore.clearFilter();
        //filter questions by selected quiz
        app.stores.QuestionStore.filter({
            property: 'quiz_id',
            value: options.id,
            exactMatch: true
        });

        //pass quiz record for setting toolbar title etc
        app.views.questionList.updateWithRecord(currentQuiz);

        app.views.quiz.setActiveItem(
            app.views.questionList, options.animation
        );

    }

Hope this helps anyone running into the same problem!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文