【问题标题】:Should I and how to transitionToRoute in a promise callback我应该以及如何在 promise 回调中进行 transitionToRoute
【发布时间】:2015-05-12 02:58:03
【问题描述】:

在 Ember 控制器中,我想调用我的 API 来创建用户,并在成功时调用 transitionToRoute。这是我目前想要的工作:

import ajax from "ic-ajax";
import Ember from "ember";

export default Ember.Controller.extend({
  actions: {  
    createAndLoginUser: function() {
      var user = { "user": this.getProperties("email", "name") };
      ajax({ url: "api/users", type: "POST", data: user })
        .then(transitionToHome);
    }   
  }
});

var transitionToHome = function() {
  this.transitionToRoute("home")
}

但是当我在方法中放置debugger 时,this 不再是控制器对象并且超出了调用transitionToRoute 的范围。

我只写过 hacky javascript,但我正在尝试学习核心概念和一些框架。这是使用承诺的正确方法吗?这是在 Ember 中进行转换的正确位置吗?

【问题讨论】:

    标签: javascript ember.js callback promise ic-ajax


    【解决方案1】:

    您的问题与 Ember 或过渡无关;这一切都与this 处理有关。最简单的解决方案就是

    .then(transitionToHome.bind(this));
    

    将转换方法放入控制器中

    您还可以考虑将transitionToHome 作为一种方法放入控制器中。然后,您可以按以下方式调用它:

    export default Ember.Controller.extend({
    
      transitionToHome: function() { this.transitionToRoute("home"); },
    
      actions: {  
        createAndLoginUser: function() {
          var self = this;
          var user = { "user": this.getProperties("email", "name") };
          ajax({ url: "api/users", type: "POST", data: user })
            .then(function() { self.transitionToHome(); });
        }   
      }
    
    });
    

    这可能是一种更简单的方法,更易读,不需要推理 this 和使用 bind(但确实需要使用 self)。

    将过渡移动到路线?

    在您的问题范围之外,但有些人会说与路由相关的逻辑(包括转换)在逻辑上属于路由,而不是控制器。如果你同意,你可以重构上面的代码来做一个send

    createAndLoginUser: function() {
      var user = { "user": this.getProperties("email", "name") };
      var self = this;
      ajax({ url: "api/users", type: "POST", data: user })
        .then(function() { self.send("goHome"); });
      }
    }
    

    然后在您的路线中实施goHome 操作。或者,您可以在更高级别的路由(甚至是应用程序路由)中实现goHome,从而使其可用于任何控制器或更低级别的路由。

    将 AJAX 逻辑移至服务?

    其他人可能会说 ajax 逻辑并不真正属于控制器,而应该在服务层中,所以

    // services/user.js
    export function createUser(data) {
      return ajax({ url: "api/users", type: "POST", data: { user: data } });
    }
    
    // controller
    import { createUser } from 'app/services/user';
    
    export default Ember.Controller.extend({
      createAndLoginUser: function() {
        var data = this.getProperties("email", "name"));
        var self = this;
        createUser(data) . then(function() { self.send("goHome"); });
      }
    };
    

    使用ES6语法,我们可以避免self,简化了一点流程:

      createAndLoginUser: function() {
        var data   = this.getProperties("email", "name"));
        var goHome = () => this.send("goHome");
    
        createUser(data) . then(goHome);
      }
    

    现在这段代码开始看起来更具语义化和可读性。

    【讨论】:

    • 或者,当我尝试将其添加为控制器方法时,我收到相同的 Cannot read property 'transitionToHome' of undefined transitionToHome: function() { this.transitionToRoute("home") }, 编辑:刚刚添加了我的控制器方法代码。
    • 抱歉,有一个 this/self 问题现已修复。
    • 也感谢所有反馈!我肯定会尝试这些重构,我一直在为 Ember 文档苦苦挣扎。
    • 让这些重构工作,代码看起来很棒!我在制作它们时遇到了几件事:1)createUser import 必须是../services/user? 2) createUser 方法是导入类user 的一部分吗?除此之外,再次感谢!
    • 感谢您的跟进。您可以使用相对或绝对路径导入。前者为from '../services/user',后者为from '*appname*/services/user',将appname 替换为您的应用程序的实际名称,并假设services 位于树的顶部。在这种情况下,我更喜欢后者。写你的第二点,我的错误,导入应该是import {createUser} from ...'`。
    【解决方案2】:

    另一种解决方案是简单地使用 ES6 箭头语法来维护 this 的上下文:

    import ajax from "ic-ajax";
    import Ember from "ember";
    
    export default Ember.Controller.extend({
      actions: {  
        createAndLoginUser() {
          let user = { "user": this.getProperties("email", "name") };
          ajax({ url: "api/users", type: "POST", data: user })
            .then(() => {
              this.transitionToRoute("home");
            });
        }   
      }
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-22
      • 1970-01-01
      • 2015-04-02
      • 2010-12-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多