【问题标题】:Firebase 3-way data binding with ControllerAs syntax使用 ControllerAs 语法的 Firebase 3 向数据绑定
【发布时间】:2015-02-06 15:46:22
【问题描述】:

我正在尝试使用 firebase 和 angularfire 进行 3 路数据绑定。你可以看到我在 Plunker 中得到了什么:http://plnkr.co/edit/RGA4jZK3Y6n4RkPCHK37

app.js

angular.module('ideaBattle', ["firebase"]);

服务

angular
    .module('ideaBattle')
    .constant('FBURL', 'https://ideabattle.firebaseio.com/')
    .service('Ref', ['FBURL', Firebase])
    .factory('dataBank', function(Ref, $firebase) {
        return $firebase(Ref).$asArray();
    });

控制器

angular
    .module('ideaBattle')
    .controller('ideaListCtrl', displayIdeas);

displayIdeas.$inject = ['dataBank'];
function displayIdeas(dataBank){
    var vm = this;
    vm.ideas = dataBank;

    vm.upVote = function(idea){
        vm.ideas[idea.id].votes++;
    };
}

HTML

<div ng-controller="ideaListCtrl as vm">
    <div ng-repeat="idea in vm.ideas | orderBy: '-votes'">
        <div>
            <h2>{{idea.name}}</h2>
            <p>{{idea.desc|limitTo: 190}}</p>
            <span class="btn" ng-click="vm.upVote(idea)">Vote! <span class="badge"> {{idea.votes}}</span></span>
        </div>
    </div>
</div>

Plunker 版本:http://plnkr.co/edit/RGA4jZK3Y6n4RkPCHK37

它的作用是从 firebase 获取数据并正确显示,但是当我按下按钮调用 upVote 函数时,它只会在本地更新。我知道为什么它只能在本地工作,但我不知道如何让它也在 firebase 中更新。

我尝试过使用 $bindTo,但据我了解,它需要 $scope 才能工作,并且我正在尝试使用“Controller as vm”模式而不注入 $scope。

谁能告诉我怎么咬它?

【问题讨论】:

  • 你打过$save()吗,see the documentation
  • 据我了解,$save 是一个函数,每次我想要更新 firebase 时都需要调用它。这不是我真正想要的方法。我想要更多“一劳永逸”的三向数据绑定,以便对本地数据所做的每一次更改都会反映在 firebase 中。我知道可以使用 $bindTo($scope, "data") 方法轻松完成,但我根本不想使用 $scope,因此我的问题是,如何保持这种模式。
  • vm.ideas[idea.id].votes++; vm.ideas.$save(idea.id).then(function(ref) { ref.key() === vm-ideas[idea.id].$id; // true });
  • 这行得通 - 当然,但它仍然不是 3 路数据绑定 - 只是更新 firebase 的功能。我需要在任何我进行更改的地方调用它,但我希望它是自动的,就像它在本地(2 路数据绑定)一样。我知道这是可以做到的。我不知道怎么做。
  • 好吧,一切都只是一个函数。尝试extending Array factory,保持干燥

标签: javascript angularjs firebase angularfire


【解决方案1】:

tl;博士; — 三向数据绑定不适用于 ControllerAs 语法。 bindTo 方法需要$scope

您可以将 AngularFire 与 ControllerAs 语法一起使用,但您不能将其与具有 $bindTo 的 ControllerAs 一起使用。

$bindTo$scope 有很强的依赖关系,没有它就会崩溃。

如果您想要使用带有 ControllerAs 语法的 AngularFire 示例,请查看 this Plunker demo

  angular.module('app', ['firebase'])

  // constant for the Firebase we're using
  .constant('FBURL', 'https://<your-firebase>.firebaseio.com/todos')

  // return the Firebase ref as a service
  .service('Ref', ['FBURL', Firebase])

  // return the Todos from Firebase by returning the
  // array from the factory 
  .factory('Todos', function(Ref, $firebase) {
    return $firebase(Ref).$asArray();
  })

  // inject the Todos and assign them to "this"
  // for the ControllerAs syntax
  .controller('MainCtrl', function(Todos) {
    this.todos = Todos;
  });

【讨论】:

  • 如果你看一下我的代码,你会发现,你提到的这个 plunker 正是我构建的那个。但问题仍然存在。我不知道如何让它使用 3-way 数据绑定。
  • 正如我在回答中提到的,你不能将 AngularFire 和 ControllerAs 语法与 3 路数据绑定一起使用。 bindTo 依赖于 $scope,这违背了 ControllerAs 语法。
  • 是 bindTo 获得 3 路数据绑定的唯一方法吗?没有办法解决吗?
  • bindTo 方法设置自动 3 路数据绑定。但是,您仍然可以像上面的示例一样创建 Firebase 数组。每当发生更改时,您都可以手动添加/更新数组。更改将更新 Firebase,它会自动更新数组并重新绑定您的模板。
【解决方案2】:

John Papa talks 关于在每个控制器中使用 var vm = this; 语法而不是 $scope 的目的之一是使 $scope 的使用成为有意识的选择。在这种情况下,我们需要包含 $scope。

我在his answer 中使用了 David East 的 plunkr,并对其进行了一些修改。它不是完美,因为它依赖于 controllerAs 的值是 'vm'。

http://plnkr.co/edit/vLLaa7QJvfryYRD7cZvO?p=preview

  .controller('MainCtrl', function(Todos, $scope) { /* Add $scope */
    var vm = this;

    vm.todos = Todos.all();

    vm.lonelyTodo = Todos.get('-JeNOtYPv7AZmVAoZ1bu');
    vm.lonelyTodo.$bindTo($scope, 'vm.lonelyTodo'); /* Add three way binding */
  });

【讨论】:

  • 这是一个很好的解决方法,特别是如果您使用 TypeScript,它提倡使用带有 ControllerAs 的类。
  • 我认为这是人们正在寻找的答案,而且方法也正确。
【解决方案3】:

以 ES6/JS2015 systax 为例,在上面的响应中添加一些说明。

export class SomeController {
  constructor($firebaseObject, $scope) {
  'ngInject';    

  //using the firebase SDK 3.0 
  let obj = $firebaseObject(firebase.database().ref().child('someKey'));

  // To make the data available in the DOM, assign it to
  // 'this.data' accessible from DOM as $ctrl.data
  this.data = obj;

  // For three-way data bindings, you will still need to inject '$scope'
  // but you can alias your controller on $scope
  obj.$bindTo($scope, '$ctrl.data');

  // Why does this work? 
  // This works because angular 1x puts controllerAs
  // on top of $scope. So '$scope.$ctrl.data' is the same as 'this.data'.
  // Note: $ctrl is the default controllerAs syntax if not specified,
  // just change $ctrl to your defined controllerAs ailias if 
  // specified. 
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-04-05
    • 2015-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-07
    相关资源
    最近更新 更多