2

I'm very new at angularjs and I'm in trouble,
I have html like this:

<section class="content" ng-app="offer">
    <div ng-controller="OfferController">
    ...
    <input name="Attachment" type="file" class="file_up" onchange="angular.element(this).scope().change(this)" ng-model="Attachment" />
    <span>{{Attachment}}</span> //i can't get it
    ...
    </div>
</section>

and script:

var myApp = angular.module('offer', []);

myApp.controller('OfferController', ['$scope', function ($scope) {
    $scope.change = function (element) {
        if (element.files.length > 0) {
            $scope.Attachment = element.files[0].name;
        }
        else {
            $scope.Attachment = "";
        }
        console.log($scope.Attachment); // I can get changed value in console
    }
}]);

image:
i can not get span with value

I can get changed value in console but I can't get in html side when input's value change. Thank you so much in advance for any help.

Engin Üstün
  • 1,118
  • 11
  • 18

2 Answers2

6

Since you change model from outside Angular's digest cycle, you have to inform framework manually that it must run watchers again. You can use $scope.$apply() for this:

$scope.change = function (element) {
    if (element.files.length > 0) {
        $scope.Attachment = element.files[0].name;
    }
    else {
        $scope.Attachment = "";
    }
    $scope.$apply();
}

Or more concise:

$scope.change = function(element) {
    $scope.$apply(function() {
        $scope.Attachment = element.files.length ? element.files[0].name : '';
    });
}

Demo: http://plnkr.co/edit/6quQlHJIvdD3QwtOhHrB?p=preview

dfsq
  • 191,768
  • 25
  • 236
  • 258
1

EDIT: As @dfsq pointed out in a comment, ng-change doesn't work out of the box for a file input, so I edited to include an alternative solution instead.

You could write a custom directive to handle a file input yourself, and make it update the property binding in ng-model (only one-way though).

.directive('input', function () {
  return {
    restrict: 'E',
    require: '?ngModel',
    link: function(scope, element, attr, ctrl) {
      if (!ctrl || attr.type !== 'file') {
        return;
      }

      var listener = function() {
        var file = element[0].files[0];
        var value = file && file.name;

        if (ctrl.$viewValue !== value) {
          scope.$apply(function() {
            ctrl.$setViewValue(value); // update ng-model
          });
        }
      };

      element.on('change', listener);
    }
  }
})

This way, the onchange or ng-change is not needed, when user choose a file, the file name should be set to the property in ng-model right away.

<input type="file" name="Attachment" ng-model="Attachment" ng-change="change()" />
<span>{{ Attachment }}</span>

Example Plunker: http://plnkr.co/edit/K3ZLoqNUPbo991b9ooq3?p=preview

Original answer: (this doesn't work for input type="file")

Instead of onchange, you should use ng-change instead.

Try changing this:

onchange="angular.element(this).scope().change(this)"

To this:

ng-change="change($event.target)"

Hope this helps.

runTarm
  • 11,537
  • 1
  • 37
  • 37
  • 1
    Yes, it would be correct approach. Unfortunately `ngChange` does not support input type file. See [here](https://github.com/angular/angular.js/blob/48b34ddb79d8e65cbdd0aa0ef15189a904887220/src/ng/directive/input.js#L866). – dfsq Aug 20 '14 at 16:41
  • thanks, It did not help my question but gave up the idea for something else. upvoted:) – Engin Üstün Aug 20 '14 at 17:26
  • @dfsq Oh, thanks for letting me know. I will edit my answer to include alternative working solution. – runTarm Aug 20 '14 at 18:06