这种架构在Angular 1.2及更高版本下是否仍然有效

时间:2014-06-12 12:48:35

标签: javascript ruby-on-rails angularjs resources

有很多使用$ resource的代码示例。我遇到了这个,代码很清楚:https://github.com/apotry/stockwatch

我喜欢这个例子,因为:

  • 它与Rails后端交互,这就是我使用Angular
  • 的方式
  • 它使用$ resource
  • 使用非休息路线(ohlc)
  • 代码很干净

调用定义的函数非常简单,如下面的控制器代码所示,但是在工厂中嵌入保存是个好主意吗?

我的问题是:现在Angular 1.2+包含了承诺,这种类型的代码是否仍然有效并被认为是一种好的做法?这段代码如何响应错误状态?

此处定义了资源

app.factory('Stock', ['$resource', function($resource) {
  function Stock() {
    this.service = $resource('/api/stocks/:stockId', {stockId: '@id'}, {'update': { method: 'PUT' }});
  };
  Stock.prototype.all = function() {
    return this.service.query();
  };
  Stock.prototype.delete = function(stId) {
    return this.service.remove({stockId: stId});
  };
  Stock.prototype.create = function(attr) {
    return this.service.save(attr);
  };
  Stock.prototype.update = function(attr) {
    return this.service.update(attr);
  };
  Stock.prototype.ohlc = function(stId) {
    return $resource('/api/stocks/:stockId/ohlc', {stockId: '@id'}).get({stockId: stId});
  }
  return new Stock; 
}]);

以下是删除,创建和自定义路由(ohlc)的示例:

  $scope.requestOHLC = function (stockid) {
    return Stock.ohlc(stockid);
  }

  $scope.createStock = function() {
    $scope.fetchYahooFinanceData($filter('uppercase')    ($scope.newCompany["symbol"])).then(function(result) {
      $scope.error = false;
      $scope.stocks.push(Stock.create(result));
      $scope.newCompany = '';
    }, function(error) {
      $scope.error = true;
    });
  };

  $scope.deleteStock = function(id, idx) {
    Stock.delete(id);
    $scope.stocks.splice(idx, 1);
  };

修改

我正试图找出一种简单明了的做法,即在角度中使用基于资源的休息路线。

与上面的代码不同,但基于它。假设下面的代码使用的服务与上面的工厂基本相同。在此示例中,我调用一个REST资源来创建新资源(rails表条目),然后将新创建的id传递给另一个调用。请注意, createPanelHeader 引用 $ scope.selector.paneldata.primer3_parameter_id 范围变量。不确定这是否也是一种好习惯。

除非我使用 $ promise.then ,否则我发现这不起作用,但这看起来有点令人费解。我是在正确的轨道上吗?

// Section: Create Panel header
createPrimer3Parameter = function() {
    primer3_parameter = Primer3Parameter.create().$promise.then(function(primer3_parameter){
    $scope.selector.paneldata.primer3_parameter_id = primer3_parameter.id;
    createPanelHeader();
    }, function() {
      alert('Error creating primer3parameter');
    })
};

COMMENT

我真的只想尝试一种从Rails API访问REST资源的简单方法,最多只有一级嵌套。我想我错过了一些看似非常困难的东西。

到目前为止我所听到的不是使用$资源,即使在1.2以下。我应该使用原始$ http或Restangular。

此外,似乎有一些1.2更改会影响Restangular。解决方案对我来说有点像黑客攻击:

https://github.com/mgonto/restangular#using-values-directly-in-templates

更新

我没有100%清楚地离开,所以我发布了一笔赏金:https://bountify.co/write-an-angular-service-for-these-rails-routes-using-restangular

2 个答案:

答案 0 :(得分:7)

  

此类代码是否仍然有效且被视为良好做法?

此代码有效,但considered deprecated as of 1.2.0-rc3。它适用于角度1.2和1.3的所有版本,最高可达but not including 1.3.0-beta10, where automatic promise unwrapping has been removed

$scope.stocks.push(Stock.create(result));

在上面的一行中,您已在$scope上创建了一系列承诺对象。然后in index.html.erb直接通过stock迭代器:

引用承诺
<li ng-repeat="stock in stocks">
      <div id='symbol'>
        {{stock.symbol}}
      </div>

处理承诺的非弃用方式不允许您直接绑定到这样的承诺。

  

此代码如何响应错误状态?

该应用正在处理错误:

}, function(error) {
  $scope.error = true;
});

在这里:

<div ng-show="error">
    There was a problem with the Yahoo Finance API. Please try again later.
</div>

对于错误处理,您不会直接绑定承诺,因此这适用于所有版本的角度。

更好的方法?

首先,在 stockwatch 示例中保存javascript目录结构。然后,follow this directory structure代替。最后,将Restangular集成到您的项目中。创建一个stockModel工厂,在内部实例化Restangular对象,但返回在promise解析后将填充的对象(model)。不是在partial中绑定promise,而是绑定未填充的结果对象。

.factory('stocksModel', function (Restangular) {
  var model = {};
  var rest_stocks = Restangular.all('stocks');

  model.doSomethingRESTful = function (...) {
    // return a promise in case the controller needs it
    return rest_carts.some_restangular_method(...)
      .then(function() {
        model.some_data_which_was_acquired_RESTfully = ...;
      });
  };

  return model;
});

在您的控制器中:

$scope.stocks = stocksModel;

在你的部分:

{{stocks.some_data_which_was_acquired_RESTfully}}

答案 1 :(得分:2)

直言不讳

没有。如果可能的话,我会改进代码,以便更易于维护并使用Angular更新到目前为止。让我解释为什么这是一个好主意。 。

为什么你的生活如此艰难?

Angular是一个很棒的框架,可以让您通过简单的解决方案解决相当复杂的问题。 Angular的黑暗面是如果你走出人迹罕至的道路,很容易过度设计解决方案。 Angular暴露了很多内部结构,所以它很诱人(而且很有趣!)用它来捣乱而不是去寻找简单的路线。

成长的痛苦

我相信你所面对的是由于Angular在项目成熟时不断增长的痛苦。许多侧面项目如雨后春笋般出现,以修复已堵塞的漏洞。

Rails和Angular,快速的朋友

所以我的基础是我如何使用Rails和Angular。这些示例来自pet project that is not going anywhere。不幸的是,这都是coffeescript,所以希望不会给你带来麻烦。它的结构是我发现最好的Rails作品,同时保持Angular的精神和乐趣。

* app/assets/javascripts
   * app
       * project_name_app.js.coffee.erb 
       * controllers
           * controllers.js 
       * directives 
           * directives.js
       * filters    
           * filters.js
       * resources  
           * resources.js
       * services
           * services.js

滑轨&#39;资产管道使用包含的application.js包装所有内容:

//= require app/project_name_app

app/project_name_app.js.coffee.erb中,它使用包含

加载所有目录
#= require_self
#= require app/controllers/controllers
#= require app/directives/directives
#= require app/filters/filters
#= require app/resources/resources
#= require app/services/services

最后,每个子目录js(controllers.js,directives.js,filters.js,resources.js,services.js)只是加载该目录中的所有内容:

//= require_tree .

通过此设置,首先加载project_name_app.js.coffee.erb,设置Angular,依赖项和应用程序配置。然后加载控制器,指令,过滤器等。其中一个好处是,由于require_tree,自动包含了添加到子目录的新javascript。

保持$ resource简单

最好的$资源是RESTFUL。这意味着它是示例URL,并且功能根据请求的http方法而更改。缺点是,如果您有不同的URL,您可能需要多个资源。 users_resource.js.coffee

中的一个示例
angular.module("DeployerApp.resources").factory "Users", ($resource) ->
  $resource "/users.json", {},
    index:
      method: "GET"
      isArray: true
      type: "User"


angular.module("DeployerApp.resources").factory "User", ($resource) ->
  $resource "/users/:user_id.json", {},
    show:
      method: "GET"
    update:
      method: "PUT"

angular.module("DeployerApp.resources").factory "CurrentUser", ($resource) ->
  $resource "/users/current.json", {},
    show:
      method: "GET"

要获取所有用户,请致电Users.index()。要获得单个用户,请致电User.show( user_id: 1 )。最后,我经常使用的方便$资源来获取当前经过身份验证的用户CurrentUser.show()

非常直观且易于阅读,避免必须拥有模型。每个User $资源都可以单独测试。

Angular已准备好开展工作

如果你在处理多个回复时有一些复杂的杂耍行为,你真的只需要开始与$promise混蛋。我发现将成功和错误回调传递给$ resource更简单,例如:

CurrentUser.show success = (user) ->
    $scope.currentUser = user
, error = (data,status) ->
    # redirect to login

变量名称有助于使代码更具可读性,没有它们将coffeescript函数定义混合在一起。

更简单总是更好

您无需担心$ resource的$promise.then,可以让您整理一下。