angular-ui / bootstrap

PLEASE READ THE PROJECT STATUS BELOW. Native AngularJS (Angular) directives for Bootstrap. Smaller footprint (20kB gzipped), no 3rd party JS dependencies (jQuery, bootstrap JS) required. Please read the README.md file before submitting an issue!
http://angular-ui.github.io/bootstrap/
MIT License
14.28k stars 6.73k forks source link

$modal breaks forms b/c of transclusion #969

Closed boneskull closed 10 years ago

boneskull commented 11 years ago

Say I instantiate a modal:

$modal.open({
  controller: 'MyCtrl'
});

In my modal, I have a form:

<form name="myForm">...</form>

Because of transclusion, myForm is not available on MyCtrl's scope and I can't check for $valid, for example. A workaround I've found is to simply put an ng-controller="MyCtrl" within my modal template itself, and do this:

$modal.open({
  controller: function($scope, $modalInstance) {
    $scope.$modalInstance = $modalInstance;
  }
});

...and now I can get to the instance from within MyCtrl.

This is not ideal, but I'm not sure of what the fix should be. Instead of transclusion, would it be a good idea to actually insert an ngController directive within the template/modal/window.html template itself then say, ngTransclude within a child tag? Any better way to tackle this problem?

thanks Chris

kimardenmiller commented 10 years ago

One approach that fixes this scope issue (and has helped us avoid other similar issues) is to link the model to a separate service which does not rely on the scope stack.

So in the template (in CoffeeScript): image

Which links to a service: image

pgaertig commented 10 years ago

Clever solution @matt-way. I improved it further:

<form name="$parent.form">

And it just works! I have got form entry in modal $scope and I don't have to modify my form markup inside. The only thing I don't like about this is the hacky name value.

brianmarco commented 10 years ago

Tx @pgaertig your tip worked great for me!

plentz commented 10 years ago

@AGiorgetti you closed this referencing #972, and then @pkozlowski-opensource closed it referencing #981 which I don't think it's related to this one and this one should be re-open. Am I wrong? :sweat:

AGiorgetti commented 10 years ago

Hi, i didn't close anything, the reference at #972 was made because the problem reported there (a typeahead malfunction inside a modal) was related to the issues caused by the use of transclusion in the modal dialog. As of now I'm using a custom made version of the modal dialog which does not use transclusion at all, I'm just doing it manually playing with the templates (as I did in the past with the 'patched' version posted above at the time).

pkozlowski-opensource commented 10 years ago

@plentz we've got a work-around in master https://github.com/angular-ui/bootstrap/commit/0b31e8658e9a9520e8d5ccfcea23fa040f032562, not released yet, so no need to re-open anything...

plentz commented 10 years ago

@AGiorgetti thanks!

@pkozlowski-opensource coool! thanks a lot!

kulicuu commented 10 years ago

boneskull thx for the brilliant workaround !

LeleDev commented 10 years ago

I'm still having the same issue... 0b31e86 hasn't been released yet?

LeleDev commented 10 years ago

Ok, I've compiled the master version with grunt and now it works. Hope that ui-boostrap 0.12 will be released soon!

KKrisu commented 9 years ago

I just want to confirm - After upgrading ui-bootstrap to 0.12 it works correctly!

devendher commented 9 years ago

check it this plunker might be it will helpful and i think it is complete solution that really what do you want http://plnkr.co/edit/ZM3UUt16P3cRainp0LK3?p=preview

solerman commented 8 years ago

I was fighting over ng-model/ng-form myself this days. My problem was a bit different but also cased by the way scopes/controllers are handled. Basically I have a directive to watch from the parent form for changes and warn the user if he's about to leave the page without saving and that wasnt working if you only changed the modal's values. The workaround:

In the parent controller inject your form

   modalInstance = $modal.open({
        resolve: {
          containerForm: function () {
            return $scope.containerForm;
          }
        }
      });

And in the modal's template set the parent form before any control has the chance to initialize

    <ng-form name="$parent.modalForm">
        <any ng-init="$parent.modalForm.$$parentForm = containerForm"/>
icfantv commented 8 years ago

@solerman, I should point out that using ng-init outside the very limited, documented areas is not correct.

Also, doing this with your form is not correct. You should be returning the model from the form in the modal as a result of the $promise from the modal and then, if needed, update your form's model with that data.

solerman commented 8 years ago

The problem is, with bindings the model is already updated in the model. To do what you say I would need to clone the (very complex) model, provide it to the modal and then hand-copy all the values back. For every modal.

icfantv commented 8 years ago

@solerman, that sounds like an issue with design and UX rather than our library. do you need to send the entire model to the modal or can you just send the bit that the model intends to edit?

For the record, this is a very common paradigm - say, having a grid of data and then editing a grid item in a modal.

solerman commented 8 years ago

@icfantv the parent its a dashboard and the modal its just for a single dashboard item. There is a lot of stuff to configure in the item, I ain't sending the entire dashboard but just a single item. Think a bar chart, all the series, axis titles, colors, ranges, etc.

icfantv commented 8 years ago

@solerman, without knowing exactly what you're using the modal to configure, it's hard to make a recommendation. It sounds like you're using the modal to configure chart options, but that's just a guess.

I can certainly appreciate not wanting to copy a "huge" model object. The only other options I can think of are:

  1. Don't copy the model, rather, send it live and use a cancel to restore the model, or
  2. Don't use a modal. Rather, use a physically separate details page. This would depend on the amount of data that needs to be edited.

I still think this boils down to a design and UX issue and not the library. We do get a lot of issues surrounding the use of parent forms wrapping "compartmentalized" forms (tabs, accordions, etc...). There are ways of working around our replace: true directives, including an example in our tabs demo - but in general, I'd argue that doing this is a somewhat bad approach. Part of that is due to how angular form validation was architected for 1.x. I don't know if or how this changes for ng2.