vitalets / angular-xeditable

Edit in place for AngularJS
http://vitalets.github.io/angular-xeditable
MIT License
1.91k stars 402 forks source link

$watch of nested directive is not triggered when form's onaftersave get called #764

Open sinall opened 4 years ago

sinall commented 4 years ago

I'm trying to create a duration editor which could represent "x days x hours x minutes x seconds" for a number which stores total seconds.

So the model totalSeconds is a number, and I create object duration of class Duration in the directive, then use 4 editable-text for those 4 properties.

In link method of the directive, I create scope.duration model and watch the object duration, the callback recalculates and updates the binding model totalSeconds.

When saving,

  1. duration.days gets called first
  2. form's onaftersave gets called
  3. $watch callback for duration (or duration.days) gets called

So I'm not able to save the updated totalSeconds in step 2.

Is there a way to let step 3 done before step 2?

sinall commented 4 years ago

Currently I have to use $timeout with 1 second delay in onaftersave to let $watch callback run first.

ckosloski commented 4 years ago

Maybe use onbeforesave instead? A plunker/jsfiddle might be useful as well to see what the issue is.

sinall commented 4 years ago

http://jsfiddle.net/e974t8qr/3/

ckosloski commented 4 years ago

I took a look at this and didn't see anything obvious. Using setTimeout does fix the issue

setTimeout(function () {
    alert("validatyPeriod: " + $scope.validatyPeriod + " seconds");
  }, 100);

Couldn't find anything else that worked.

sinall commented 4 years ago

When you submit editable form it performs following steps:

  1. call child's onbeforesave
  2. call form's onbeforesave
  3. write data to local model (e.g. $scope.user)
  4. call form's onaftersave
  5. call child's onaftersave

I guess the problem occurs in step 3.

sinall commented 4 years ago

For someone meets the same problem, here's what I'm doing now as a workaround:

link: function(scope, element, attrs) {
    // ...
    var formElement = element.parents('form');
    var oldCallbackName = formElement.attr('onaftersave').replace('()', '');
    var oldCallback = formElement.scope()[oldCallbackName];
    formElement.scope()[oldCallbackName] = function() {
        $timeout(function() {
            oldCallback();
        }, 100);
    };
},

By using this approach, you don't need to change the form's onaftersave callback.