Textalk / angular-schema-form-datepicker

Datepicker add-on for Angular Schema Form using pickadate!
MIT License
43 stars 57 forks source link

question regarding ng-model="$$value$$" #3

Closed etodanik closed 10 years ago

etodanik commented 10 years ago

Since the $$value$$ isn't on the controller scope, what the heck is it?

I'm trying to adjust this $$value$$ from a controller scope I created to wrap a file upload field I'm making , and being able to put stuff in $$value$$ is my missing link.

davidlgj commented 10 years ago

It's magic.

:D Yes I can see that it could be a bit confusing. Basically it's hard to dynamically bind a value against a ng-model, and I didn't want to end up doubling the number of watches by using an intermediary value on scope or a isolated scope with double binding. What I ended up doing was just before inserting the template I do a string replacement of $$value$$ and place whatever is the key, so we end up with a nice looking ng-model.

You can see the code here. https://github.com/Textalk/angular-schema-form/blob/development/src/services/decorators.js#L56

etodanik commented 10 years ago

Alright, so - I kinda get what happens, and I see that you basically replace it with a reference to the model variable on $scope. I wonder, however, how did something I've done work.

I basically needed a file upload interaction, so instead of making my own directive that contained the upload functionality, I set ng-controller on the parent div, kind of like this:

<div class="form-group" ng-controller="FileCtrl" ng-class="{'has-error': hasError()}">
  <label class="control-label" ng-show="showTitle()">{{form.title}}</label>

  <input ng-show="form.key"
         style="background-color: white"
         type="file"
         class="form-control"
         ng-file-select="onFileSelect($files)" />

  <span class="help-block">{{ (hasError() && errorMessage(schemaError())) || form.description}}</span>
</div>

Then, inside the JS file I did something like:

angular.module('schemaForm').config(
['schemaFormProvider', 'schemaFormDecoratorsProvider', 'sfPathProvider',
  function(schemaFormProvider,  schemaFormDecoratorsProvider, sfPathProvider) {

    var file = function(name, schema, options) {
      if (schema.type === 'string' && (schema.format === 'file')) {
        var f = schemaFormProvider.stdFormObj(name, schema, options);
        f.key  = options.path;
        f.type = 'file';
        options.lookup[sfPathProvider.stringify(options.path)] = f;
        return f;
      }
    };

    schemaFormProvider.defaults.string.unshift(file);

    //Add to the bootstrap directive
    schemaFormDecoratorsProvider.addMapping(
      'bootstrapDecorator',
      'file',
      'directives/decorators/bootstrap/file/file.html'
    );

    schemaFormDecoratorsProvider.createDirective(
      'file',
      'directives/decorators/bootstrap/file/file.html'
    );
  }
]);

angular.module('schemaForm').controller(
'FileCtrl',
['$scope', '$upload',
  function($scope, $upload) {
    $scope.onFileSelect = function($files) {
      for (var i = 0; i < $files.length; i++) {
        var file = $files[i];
        $scope.upload = $upload.upload({
          url: '/upload',
          method: 'POST',
          file: file,
        }).progress(function(evt) {
          console.log('percent: ' + parseInt(100.0 * evt.loaded / evt.total));
        }).success(function(data, status, headers, config) {
          // file is uploaded successfully
          $scope.model[$scope.form.key[0]] = data;
        });
      }
    }
  }
]);

Now - my question is why the )$()$ does it work? :) Also, why do I "magically" have the model on my $scope? Line 46 shouldn't work, but it does. How did form and model magically make it onto my freshly created controller scope?

davidlgj commented 10 years ago

Scope inheritance to the rescue!

The form is exported on scope by the decorator directive (created by the factory service in decorators.js ) https://github.com/Textalk/angular-schema-form/blob/master/src/services/decorators.js#L47

The model object is exported on scope by sf-schema directive so that ng-model has something to bind to. This means $scope.model[$scope.form.key[0]] = data; works for you since you have a flat structure, but add some arrays or objects and it will fail. The safest bet is to do a directive that requires the ng model controller. That way you can also invalidate the form if something goes wrong with the upload.

etodanik commented 10 years ago

So you mean , construct a directive that effectively wraps the file upload directive into something of my own, and not complicate the actual decorator?

davidlgj commented 10 years ago

Yes exactly. If you do a directive that plays nicely with ng-model it should just work. And on the plus side you get a file upload directive you can reuse elsewhere.