【问题标题】:Ember.js not updating modelEmber.js 不更新模型
【发布时间】:2014-12-14 11:07:22
【问题描述】:

最终更新Kalman Hazins 为我指明了正确的方向,计算属性没有被调用,因为它没有在屏幕上呈现,所以它不是“必要的” "重新计算它。我将在此处包含控制器的最终代码:

App.QuestionController = Ember.ObjectController.extend({
    isEditing : false,

    resetIsEditing : function() {
        this.set('isEditing', false);
    }.observes('model.id'),

    canEditQuestion : function() {
        return this.get('author.id') === App.currentUser;
    }.property('author.id')
}

更新:下面的Raymond Liu 提供了一个“足够好”的解决方案 ,它并没有真正回答“为什么会发生这种情况”的问题,但它是迄今为止我所拥有的最好的。


我正在学习 Ember.js,遵循 this 的书并进行一些更改。在我的控制器中,我有一个绑定到模型的属性,但是当我更改此类模型时,该属性不会更新。

这是控制器:

App.QuestionController = Ember.ObjectController.extend({
    isEditing : false,

    canEditQuestion : function() {
        this.set('isEditing', false);
        return this.get('author.id') === App.currentUser;
    }.property('model')
});

这是模板:

<script type="text/x-handlebars" id="question">
    {{#if isEditing}}
        <!-- edit question form -->
    {{else}}
        <p id="question">{{question}}</p>
        {{#if canEditQuestion}}
            <a href="#" {{action "toggleEditQuestion"}}>Edit question</a>
        {{/if}}
    {{/if}}
</script>

请注意,如果我将 {{else}} 分支内容移动到 {{#if isEditing}} 之前,它会按预期工作(但不是我想要的)。

也许question 是一个嵌套路由这一事实很重要:

App.Router.map(function() {
    this.resource('questions', function() {
        this.resource('question', { path : '/:question_id' });
    });
});

我想要的是,即使我已经在编辑问题,如果我更改模型,isEditing 属性应该返回到false,并且不会显示问题表单。显然,如果我总是提出问题,我可以解决它,但这不是我想要的。我错过了什么?

编辑:我正在添加 questionuser 模型的代码:

App.Question = DS.Model.extend({
    title : DS.attr('string'),
    question : DS.attr('string'),
    date : DS.attr('date'),
    author : DS.belongsTo('user', { async : true }),
    answers : DS.hasMany('answer', { async : true }) 
});

App.User = DS.Model.extend({
    fullname : DS.attr('string'),
    email : DS.attr('string'),
    questions : DS.hasMany('question', { async : true })
});

App.currentUser 属性在sign_in 控制器中设置:

App.SignInController = Ember.Controller.extend({
    needs : [ 'application' ],

    actions : {
        signIn : function() {
            var email = this.get("email");
            var userToLogin = App.User.FIXTURES.findBy("email", email);

            if(userToLogin === void 0) {
                alert("Wrong email!");
                this.set("email", "");
            }
            else {
                localStorage.currentUser = userToLogin.id;
                App.set('currentUser', userToLogin.id);
            }
        }
    }
});

PS:我的应用程序的完整代码可在https://github.com/goffreder/emberoverflow获得

PS2:我设法获得了我的应用程序的功能 jsFiddle。要复制,您必须使用“tom@dale.com”电子邮件登录。然后,如果您单击第一个答案,您应该会看到一个切换问题表单的“编辑问题”链接。现在,打开该表单,如果您更改问题,该表单仍然可用,新问题作为内容,这是我想要避免的行为。

【问题讨论】:

  • 你不想author.get('id')吗?除了答案中提出的有关正确编写依赖项的其他要点之外。请记住,.property('model') 并不意味着模型中的某些内容发生了变化,而是意味着模型本身——模型对象——变成了不同的模型对象。
  • 编辑:对不起,目标错误^_^我为什么要author.get('id')?这是访问属性的更好方法吗?我知道计算属性依赖于整个模型的不同,而不是它的单个属性,似乎如果我不直接用它的模板渲染它,模型就不会改变。也许应该是这样吧,我不知道(这就是我问的原因^_^)
  • 在这点上完全同意@torazaburo,一定要正确指定你的依赖。此外,您的模板逻辑没有意义。如果canEditQuestion 为真,您想检查isEditing,而不是相反。此外,您不想触发计算属性中的属性更改。观察者这样做,并且属性应该只用于计算有问题的属性。最后,计算属性只有在被访问时才会被计算,因此将其嵌套在以 false 开头的条件模板中意味着它永远不会被属性更新。
  • @AdamRobertson:“正确指定依赖项”是什么意思?另外,我明白你关于模板的观点,但如果我正在编辑,我不希望呈现{{question}} 模板,所以我必须先检查isEditing。还是我错过了什么?
  • 正如@torazaburo 提到的,依赖是author.id,而不是model。您也无法指定 App.currentUser 的依赖项,因为您在计算属性中使用了对它的全局引用,而且我很确定观察者不适用于全局变量。至于#if 块,您的最终编辑应该注意这一点。我再怎么强调也不过分,以避免在计算属性定义中修改控制器/模型——它更干净,更容易测试。

标签: javascript ember.js ember-model


【解决方案1】:

@goffredder 和@Raymond Liu,canEditQuestion 函数/属性未触发的原因如下。

在 Ember.js 中,(计算的)属性评估是“神奇的”,但众所周知 - “神奇”可能很昂贵。因此,计算属性的值被缓存,因此“魔术”不必一直发生,除非发生变化,否则不会重新计算缓存值。不仅如此,如果该属性没有显示在屏幕上 - 为什么还要重新计算它?请参阅 this jsbin 以了解我在说什么。请注意lazyPropDep 是如何永远不会更新的,因为lazyDep 属性永远不会显示在屏幕上。

现在,回到你的例子。 canEditQuestion 属性在您编辑问题时不会呈现到屏幕上(因为它位于 else 块中)。因此,将 isEditing 重置为 false 的 canEditQuestion 函数永远不会被调用。

我认为您需要将重置逻辑放入observer,同时将其他逻辑留在属性中,如下所示:

resetIsEditing : function() {
  this.set('isEditing', false);
}.observes('model.id'),

canEditQuestion : function() {
  return this.get('author.id') === App.currentUser;
}.property('model'),

这样每次新模型(具有新模型 ID)被加载到控制器中(即使之前的模型处于编辑模式),观察者代码都会触发将 isEditing 属性重置为 false

【讨论】:

  • 这就是我想读的,非常感谢!我认为这是不渲染某些东西的问题,但我认为这是模型的模板,而不是属性本身。谢谢你的解决方案和解释^_^
【解决方案2】:

更新:我误解了你的问题。您想在回答另一个问题时禁用表格,对吗?在您的 question_routs.js 文件中,添加以下内容:

App.QuestionRoute = Ember.Route.extend({
  actions: {
    didTransition: function() {
      this.controller.set('isEditing', false);
      return true; // Bubble the didTransition event
    }
  }
})

当您转换到另一个问题时,这些代码会将“isEditing”属性设置为 false。 我注意到如果 isEiting 属性设置为 true,切换到另一个问题时不会调用 canEditQuestion 函数/属性,我认为这正是需要解决的问题。我也不知道为什么。

【讨论】:

  • 谢谢,这种行为正是我想要的。不过,我会暂时不回答这个问题,因为我想知道为什么(正如您也注意到的)如果isEditing 为真,则不会调用canEditQuestion 进行模型更改。但你的回答绝对“感觉”是对的^_^
【解决方案3】:

看起来您的计算属性取决于两个变量,author.idApp.CurrentUser,它们未在依赖键列表中列出。相反,您仅将 model 列为依赖键。我不知道authormodel 之间的关系是什么,但您应该列出计算属性所需的实际属性/变量。

【讨论】:

  • 我添加了更多代码,希望这足以了解我的应用程序在做什么。但我认为只有我的计算属性的结果取决于这两个其他属性,而不是计算本身。无论我在其中做什么,都不应该计算canEditQuestion 吗?我试图在里面添加一个console.log,一旦显示问题表格,就永远不会执行......
  • 我认为您需要更基本地了解 Ember 的计算属性的目的。它们允许您使用所谓的统一访问来访问基本对象属性和存在于这些对象上的函数。它们还允许缓存函数的结果,但为了使其有效且高效地工作,您需要让 Ember 知道该函数依赖于哪些其他属性。我建议阅读以下内容:emberjs.com/guides/object-model/computed-properties 一般来说,您不能只将model 作为依赖键。
  • 那么如果我想监控整个模型的变化我应该怎么做呢?我应该使用观察者吗?如果我做对了,我在计算属性中设置isEditing 的值这一事实与本段相矛盾,对吗? “计算属性不应包含应用程序行为,并且通常不应在调用时引起任何副作用。”
  • canEditQuestion 计算属性的主体似乎是正确的。我可能会尝试设置一个 jsbin。我没有在您的存储库中运行代码,但我认为部分问题是依赖键对于该计算属性不正确,因此没有重新计算该值。
  • 如果有帮助,我在整个应用程序中添加了jsFiddle。使用“tom@dale.com”邮件地址登录。非常感谢您的帮助,非常感谢您^_^
【解决方案4】:

你可以这样做:

<script type="text/x-handlebars" id="question">
 {{#unless isEditing}}
    <p id="question">{{question}}</p>
    {{#if canEditQuestion}}
        <a href="#" {{action "toggleEditQuestion"}}>Edit question</a>
    {{/if}}
 {{else}}
    <!-- edit question form -->
 {{/unless}}
</script>

【讨论】:

  • 这似乎没有解决我的问题,它只是切换了真假分支。
  • 你试过了吗?在 Handlebars 中,最好将嵌套 if 条件放在 if 块内而不是 else 块内。如果您不想使用unless,则必须将isEditing 更改为true
  • 我已经尝试过了,它的行为方式与我的原始代码相同。既然我是 Ember 和 Handlebars 的新手,为什么使用嵌套 if 比使用 else 块更好?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多