Zach Zach - 1 year ago 38
AngularJS Question

Why is my directive updating as a result of changes in another instance of the same directive?

I created a simple directive wrapper around the HTML file input to make angular binding work. Here's my directive:

angular.module('myApp').directive('inputFile', InputFileDirective);

function InputFileDirective() {
var bindings = {
selectLabel: '@',
return {
restrict: 'E',
require: ['inputFile', 'ngModel'],
scope: true,
controllerAs: 'inputFileCtrl',
bindToController: bindings,
controller: function () {
template: `<input class="ng-hide" id="input-file-id" type="file" />
<label for="input-file-id" class="md-button md-raised md-primary">{{ inputFileCtrl.getButtonLabel() }}</label>`,
link: link

function link(scope, element, attrs, controllers) {
if (angular.isDefined(attrs.multiple)) {
element.find('input').attr('multiple', 'multiple');
var inputFileCtrl = controllers[0];
var ngModelCtrl = controllers[1];

inputFileCtrl.getButtonLabel = function () {
if (ngModelCtrl.$viewValue == undefined || ngModelCtrl.$viewValue.length == 0) {
return inputFileCtrl.selectLabel;
else {
return ngModelCtrl.$viewValue.length + (ngModelCtrl.$viewValue.length == 1 ? " file" : " files") + " selected";

element.on('change', function (evt) {

And here's the HTML

<body ng-app="myApp" ng-controller="MyController as ctrl">
<form name="ctrl.myForm">
<input-file select-label="Select Attachment" ng-model="ctrl.attachment1"></input-file>

<input-file select-label="Select Attachment" ng-model="ctrl.attachment2"></input-file>

It's pretty simple and it works - if only one is on the page. As soon as I add a second one, I notice that only the first one ever updates. If I select a file with the second one, the label updates on the first one. My suspicions are that the require ['inputFile'] is pulling in the controller for the first directive instance into the link function or something (which shouldn't happen). Even now as I type this, that doesn't really make sense to me. So what's going on here and how do I fix it?

Here's a codepen for you guys to play with and try to figure it out:

Answer Source

Your problem is not with your angular... is with you html. You are assigning the same id twice. Change your template to this:

template: `<label class="md-button md-raised md-primary">{{ inputFileCtrl.getButtonLabel() }}<input class="ng-hide" type="file" /></label>`