0

Apologies for the long post, but I am attempting to provide as much information as I can.

I have inherited a rather complex app that utilizes Angular. Because of an NDR, I cannot post code samples, and as of yet, have been unable to recreate my issue in a smaller, less complicated stand alone plnkr. I’m sure if I could, I could then figure out what I need to do to fix this issue. I know your hands are tied because I cannot post code, nor can I recreate the problem in a plnkr, but I’m going to do my best to give as much information as possible to hopefully get some general suggestions on what to look at next.

First, the code/architecture: I have a form.html. Inside that form.html, we are using ng-repeat to iterate through a list of fields pulled from the database, and displaying each field. The fields at the form level are a custom type.

<field data=“attrs.field[fieldId]” on-update”updateField” field=“field"></field>

updateField(fieldId, data) is defined in form.directive.js, and is used to update the data back to the database when it changes. This part works reliably.

form.html also contains a button that is used to clear the contents of the field.

<button class="btn btn-sm btn-danger" tooltip="Clear Field" ng-click="updateMetadataField(field._id, null)" ng-show="field.editable">

The field uses templates to generate the proper input, based upon the type. We use selects, texts, textedits, and many other custom fields. We use predictive text in many of these fields as well.

Here is one example:

<input name={{field._id}} type="text" class="form-control" ng-model="data" ng-blur="onUpdate(field._id, data)" ng-if="field.editable" typeahead="suggestion as suggestion for suggestion in field.suggestions | filter:$viewValue | limitTo:8" />

There is a field.directive.js that has its own methods used to manipulate the custom input fields that have been written. That contains:

scope: {
  data: '=',
  field: '=',
  onUpdate: '='
},

The problem: When initially loading the form, if there is data in a text field, and the user hits the Clear Field button, the database gets updated and the string is removed from the text box.

When a user first types text into a field, then leave the field, ng-blur calls updateField, and the data gets written to the database. This works fine. When a user clicks on the Clear Field button for a text or textedit field, the value in the database gets set back to null, but the string displayed in the text box doesn’t get cleared. However, if we reload the form, the text field shows empty.

At first I thought this had to do with an isolated scope inside of the fields stemming from the use of ng-repeat. However, a simple output statement of the attrs.field at the top of the form.html showed that every time the text box is updated, the parent scope is updating as well. So this doesn’t appear to be the issue.

I’ve decided that perhaps the issue is that the $modelValue of the input is getting updated, but the $viewValue is not (or at the very least we need to call $render for some reason). I’ve since been attempting to inject ngModel into the form.directive.js in order to access these variables and methods to see if I’m correct, but I’m having a heck of a time doing so.

1st attempt: I tried injecting ngModel into the form.directive.js’s directive’s argument list. When I load the form, I get the following error:

Error: [$injector:unpr] Unknown provider: ngModelProvider <- ngModel <- fieldsDirective
http://errors.angularjs.org/1.4.7/$injector/unpr?p0=ngModelProvider%20%3C-%20ngModel%20%3C-%20fieldsDirective

I’m rather new to Angular, and I found the information at the link to be rather confusing. Some help understanding what they’re talking about there would be awesome!

2nd attempt: Injecting ngModel in as an argument to the function in the link field in form.directive.js, along with a require: ’ngModel' statement in the return {} section. When I load the form, I get the following error:

Error: [$compile:ctreq] Controller 'ngModel', required by directive ‘fields', can't be found!
http://errors.angularjs.org/1.4.7/$compile/ctreq?p0=ngModel&p1=fields

When I follow this link it says that it is looking for the required directive controller on the current DOM element or its ancestor (when using require: ‘^ngModel’). However, these are being used by templates in the field used in the form. Does this qualify as being used in the current DOM element this way?

3rd attempt: Assuming that the template is the reason I cannot include ngModel, I found this: Updating ng-model within a directive that uses a template. I changed the data: ‘=‘ scope mapping to data: '=ngModel’. Unfortunately this hasn’t changed any behavior at all.

I’m stuck. Can anyone provide me some other avenues to explore, or perhaps shed light as to why my including ngModel is failing?

Thanks in advance!

Community
  • 1
  • 1
learjetta
  • 1
  • 3
  • Is `data=“attrs.field[fieldId]” on-update”updateField” field=“field"` how you actually have it in your HTML? If so, it should be ``. – Harris Nov 02 '15 at 18:38
  • Hi Harris! It's written the way you outlined. I made an error when typing. Good catch though! Thanks! – learjetta Nov 03 '15 at 19:30

2 Answers2

0

This is definitely tricky to diagnose without being able to see what you're actually doing. I would skip the ngModel injection as dangerous over-complication. I'd guess it's actually something simple at its core.

Now, my shot in the dark: Are you actually updating the $scope.data variable you're trying to work with? It looks to me like you're passing the callback updateField from the parent, which is defined in the parent. That would mean that when you reference $scope.anyVariable in the function, it's referring to the parent's $scope element (you'd be working in the parent controller's closure, not the directive's). You could have updateField take the child scope as a parameter, have the directive pass its $scope through that, and you'd know that you're actually working with the correct $scope object.

When that actual variable that's bound to ngModel is properly modified, the display should change in turn.

Harris
  • 1,775
  • 16
  • 19
  • Thanks for your response! I'm working on trying this now, but I have a question: if I also printed out {{data}} in the template that contains the text input, wouldn't that be the same scope's data as the text box? If so, then I've verified that the template's scope variable is getting updated by using this method. – learjetta Nov 02 '15 at 17:12
  • Yes, I'd say it's the same scope. A simple test- do `console.log($scope)` within the function being called. That'll give you a definitive answer on where you're working, and we can see if this line of investigation is the correct one. Perhaps you'll spot something yourself. – Harris Nov 04 '15 at 14:54
0

So we finally solved the issue.

The Clear Field button was contained inside of the Form.html, but was acting upon the input inside of the field template inside of field.html. Great for not having to repeat code, but unfortunately this just wasn't updating the value inside of the input for us when we used the Clear Field button to set it to null.

To solve, we moved the Clear Field button inside of each template, and changed around the callbacks so that updates made to ng-model in the input go to field's directive then bubble up to form's directive as required.

This fixed (or at least worked around) our issue.

Thanks!

learjetta
  • 1
  • 3