$ bind应该保存ng-repeat中添加的子数据

时间:2014-02-06 19:24:16

标签: angularjs firebase angularjs-ng-repeat filepicker.io angularfire

嗨我遇到了$ bind的问题,我绑定了一个模型并通过ng-repeat输出模型。 ng-repeat输出存储的数据,并提供一些用于添加/更改数据的字段。这些更改会反映在范围内,但不会同步到Firebase。

这是我实现$ bind的问题吗?

HTML:

<iframe id="fpframe" style="border: 0; width: 100%; height: 410px;" ng-if="isLoaded"></iframe>
<form>
  <ul>
    <li ng-repeat="asset in upload_folder" ng-class="{selected: asset.selected}">
      <div class="asset-select"><input type="checkbox" name="selected" ng-model="asset.selected"></div>
      <div class="asset-thumb"></div>
      <div class="asset-details">
        <h2>{{asset.filename}}</h2>
        <p><span class="asset-filesize" ng-if="asset.size">Filesize: <strong><span ng-bind-html="asset.size | formatFilesize"></span></strong></span> <span class="asset-filetype" ng-if="asset.filetype">Filetype: <strong>{{asset.filetype}}</strong></span> <span class="asset-dimensions" ng-if="asset.width && asset.height">Dimensions: <strong>{{asset.width}}x{{asset.height}}px</strong></span> <span class="asset-type" ng-if="asset.type">Asset Type: <strong>{{asset.type}}</strong></span></p>
        <label>Asset Description</label>
        <textarea ng-model="asset.desc" cols="10" rows="4"></textarea>
        <label>Creator</label>
        <input type="text" ng-model="asset.creator" maxlength="4000">
        <label>Release Date</label>
        <input type="text" ng-model="asset.release">
        <label for="CAT_Category">Tags</label>
        <input type="text" ng-model="asset.tags" maxlength="255">
      </div>
    </li>
  </ul>
</form>

Controller :( fpKey是存储Filepicker API密钥的常量)

.controller('AddCtrl',
  ['$rootScope', '$scope', '$firebase', 'FBURL', 'fpKey', 'uploadFiles',
  function($rootScope, $scope, $firebase, FBURL, fpKey, uploadFiles) {
    // load filepicker.js if it isn't loaded yet, non blocking.
    (function(a){if(window.filepicker){return}var b=a.createElement("script");b.type="text/javascript";b.async=!0;b.src=("https:"===a.location.protocol?"https:":"http:")+"//api.filepicker.io/v1/filepicker.js";var c=a.getElementsByTagName("script")[0];c.parentNode.insertBefore(b,c);var d={};d._queue=[];var e="pick,pickMultiple,pickAndStore,read,write,writeUrl,export,convert,store,storeUrl,remove,stat,setKey,constructWidget,makeDropPane".split(",");var f=function(a,b){return function(){b.push([a,arguments])}};for(var g=0;g<e.length;g++){d[e[g]]=f(e[g],d._queue)}window.filepicker=d})(document);
    $scope.isLoaded = false;
    // Bind upload folder data to user account on firebase
    var refUploadFolder = new Firebase(FBURL.FBREF).child("/users/" + $rootScope.auth.user.uid + "/upload_folder");
    $scope.upload_folder = $firebase(refUploadFolder);
    $scope.upload_folder.$bind($scope,'upload_folder');
    // default file picker options
    $scope.defaults = {
      mimetype: 'image/*',
      multiple: true,
      container: 'fpframe'
    };
    // make sure filepicker script is loaded before doing anything
    // i.e. $scope.isLoaded can be used to display controls when true
    (function chkFP() {
      if ( window.filepicker ) {
        filepicker.setKey(fpKey);
        $scope.isLoaded = true;
        $scope.err = null;
        // additional picker only options
        var pickerOptions = {
          services:['COMPUTER', 'FACEBOOK', 'GMAIL']
        };
        var storeOptions = {
          location: 'S3',
          container: 'imagegrid'
        };
        var options = $.extend( true, $scope.defaults, pickerOptions );
        // launch picker dialog
        filepicker.pickAndStore(options, storeOptions,
          function(InkBlobs){
            uploadFiles.process(InkBlobs, $scope.upload_folder);
          },
          function(FPError){
            $scope.err = FPError.toString();
          }
        );
      } else {
        setTimeout( chkFP, 500 );
      }
    })();
  }])

我还有一个处理来自Filepicker的输入的服务,这会在绑定的引用的firebase中创建新条目(使用Firebase方法而不是AngularFire可能会破坏绑定?)

.service('uploadFiles', ['$rootScope', 'FBURL', function($rootScope, FBURL) {
  return {
    process: function(InkBlobs, upload_folder) {
      var self = this;
      var countUpload = 0;
      // write each blob to firebase
      angular.forEach(InkBlobs, function(value, i){
        var asset = {blob: value};
        // add InkBlob to firebase one it is uploaded
        upload_folder.$add(asset).then( function(ref){
          self.getDetails(ref);
          countUpload++;
        });
      });
      // wait for all uploads to complete before initiating next step
      (function waitForUploads() {
        if ( countUpload === InkBlobs.length ) {
          self.createThumbs(upload_folder, { multi: true, update: false, location: 'uploads' });
        } else {
          setTimeout( waitForUploads, 500 );
        }
      })();
    },
    getDetails: function(ref) {
      // after InkBlob is safely stored we will get additional asset data from it
      ref.once('value', function(snap){
        filepicker.stat(snap.val().blob, {size: true, mimetype: true, filename: true, width: true, height: true},
          function(asset) {
            // get asset type and filetype from mimetype
            var mimetype = asset.mimetype.split('/');
            asset.type = mimetype[0].replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
            asset.filetype = mimetype[1];
            // add metadata to asset in upload folder
            ref.update(asset);
          });
      });
    },
    createThumbs: function(ref, options) {
      var self = this;
      // default options
      options.multi = options.multi || false;
      options.update = options.update || false;
      options.location = options.location || 'asset';
      // if pathbase is not provided generate it based on provided location
      if (!options.pathbase) {
        if (options.location === 'assets') {
          options.pathbase = FBURL.LIBRARY + "/assets/";
        } else if (options.location === 'uploads') {
          options.pathbase = "/users/" + $rootScope.auth.user.uid + "/upload_folder/";
        } else {
          throw new Error('SERVICE uploadFiles.createThumbs: options.location is not valid must be assets or uploads');
        }
      }
      var generateThumb = function(blob, path) {
        filepicker.convert( blob,
          { width: 200, height: 150, fit: 'crop' },
          { location: 'S3', access: 'public', container: 'imagegrid', path: '/thumbs/' },
          function(tnInkBlob){
            var refThumbBlob = new Firebase(FBURL.FBREF).child(path);
            refThumbBlob.set(tnInkBlob);
          },
          function(FPError){
            alert(FPError);
          },
          function(percentage){
            // can use to create progress bar
          }
        );
      };
      if (options.multi) {
        // look at all assets in provided ref, if thumbnail is mission or update options is true generate new thumb
        angular.forEach(ref, function(value, key){
          if (typeof value !== 'function' && (!value.tnblob || options.update)) {
            // thumb doesn't exist, generate it
            var blob = value.blob;
            var path = options.pathbase + key + '/tnblob';
            generateThumb(blob, path);
          }
        });
      } else {
        // getting thumbnail for a single asset
        var refAsset = new Firebase(FBURL.FBREF).child(options.pathbase + ref);
        var blob = refAsset.val().blob;
        var path = options.pathbase + ref + '/tnblob';
        generateThumb(blob, path);
      }
    }
  };
}]);

所以回顾一下,数据正在保存到/users/$rootScope.auth.user.uid/upload_folder,这是在HTML中呈现的。尽管存在绑定,HTML表单中的更改仍会反映在范围内,但不会反映在Firebase中:

var refUploadFolder = new Firebase(FBURL.FBREF).child("/users/" + $rootScope.auth.user.uid + "/upload_folder");
$scope.upload_folder = $firebase(refUploadFolder);
$scope.upload_folder.$bind($scope,'upload_folder');

为什么会这样?我的实现是不正确的还是我以某种方式破坏了绑定? $ bind甚至应该以这种方式使用ng-repeat吗?

由于

1 个答案:

答案 0 :(得分:0)

拍摄自己这是多么简单,错误在于我如何定义绑定。您无法在自身上设置绑定,您需要在范围内使用两个单独的对象...

firebase参考$scope.syncdata加载初始数据,对$scope.upload_folder所做的所有修改都将同步到firebase。

var refUploadFolder = new Firebase(FBURL.FBREF).child("/users/" + $rootScope.auth.user.uid + "/upload_folder");
$scope.syncdata = $firebase(refUploadFolder);
$scope.syncdata.$bind($scope,'upload_folder');