Problemy z zakresem w modalnym interfejsie Angular UI

80

Mam problem ze zrozumieniem / używaniem zakresów dla kątowego modułu interfejsu użytkownika.

Chociaż nie jest to od razu widoczne, mam moduły i wszystko skonfigurowane poprawnie (o ile wiem), ale te przykłady kodu w szczególności są tam, gdzie znajduję błąd.

index.html (jego ważna część)

<div class="btn-group">
    <button class="btn dropdown-toggle btn-mini" data-toggle="dropdown">
        Actions
        <span class="caret"></span>
    </button>
    <ul class="dropdown-menu pull-right text-left">
        <li><a ng-click="addSimpleGroup()">Add Simple</a></li>
        <li><a ng-click="open()">Add Custom</a></li>
        <li class="divider"></li>
        <li><a ng-click="doBulkDelete()">Remove Selected</a></li>
    </ul>
</div>

Controller.js (znowu ważna część)

MyApp.controller('AppListCtrl', function($scope, $modal){
    $scope.name = 'New Name';
    $scope.groupType = 'New Type';

    $scope.open = function(){
        var modalInstance = $modal.open({
            templateUrl: 'partials/create.html',
            controller: 'AppCreateCtrl'
        });
        modalInstance.result.then(function(response){

            // outputs an object {name: 'Custom Name', groupType: 'Custom Type'}
            // despite the user entering customized values
            console.log('response', response);

            // outputs "New Name", which is fine, makes sense to me.                
            console.log('name', $scope.name);

        });
    };
});

MyApp.controller('AppCreateCtrl', function($scope, $modalInstance){
    $scope.name = 'Custom Name';
    $scope.groupType = 'Custom Type';

    $scope.ok = function(){

        // outputs 'Custom Name' despite user entering "TEST 1"
        console.log('create name', $scope.name);

        // outputs 'Custom Type' despite user entering "TEST 2"
        console.log('create type', $scope.groupType);

        // outputs the $scope for AppCreateCtrl but name and groupType
        // still show as "Custom Name" and "Custom Type"
        // $scope.$id is "007"
        console.log('scope', $scope);

        // outputs what looks like the scope, but in this object the
        // values for name and groupType are "TEST 1" and "TEST 2" as expected.
        // this.$id is set to "009" so this != $scope
        console.log('this', this);

        // based on what modalInstance.result.then() is saying,
        // the values that are in this object are the original $scope ones
        // not the ones the user has just entered in the UI. no data binding?
        $modalInstance.close({
            name: $scope.name,
            groupType: $scope.groupType
        });
    };
});

create.html (w całości)

<div class="modal-header">
    <button type="button" class="close" ng-click="cancel()">x</button>
    <h3 id="myModalLabel">Add Template Group</h3>
</div>
<div class="modal-body">
    <form>
        <fieldset>
            <label for="name">Group Name:</label>
            <input type="text" name="name" ng-model="name" />           
            <label for="groupType">Group Type:</label>
            <input type="text" name="groupType" ng-model="groupType" />
        </fieldset>
    </form>
</div>
<div class="modal-footer">
    <button class="btn" ng-click="cancel()">Cancel</button>
    <button class="btn btn-primary" ng-click="ok()">Add</button>
</div>

Tak więc moje pytanie brzmi: dlaczego zakres nie jest podwójnie powiązany z interfejsem użytkownika? i dlaczego thisma dostosowane wartości, ale $scopenie ma?

Próbowałem dodać ng-controller="AppCreateCtrl"element div body w create.html, ale spowodowało to błąd: „Nieznany dostawca: $ modalInstanceProvider <- $ modalInstance”, więc nie mam szczęścia.

W tym momencie moją jedyną opcją jest przekazanie obiektu z powrotem za pomocą this.namei this.groupTypezamiast używania $scope, ale wydaje się to złe.

coblr
źródło
Dobra dyskusja na temat zakresu modalnego tutaj: github.com/mgcrea/angular-strap/issues/14
steampowered

Odpowiedzi:

60

Mam swoje do pracy w ten sposób:

var modalInstance = $modal.open({
  templateUrl: 'partials/create.html',
  controller: 'AppCreateCtrl',
  scope: $scope // <-- I added this
});

Brak nazwy formularza, nie $parent. Używam AngularUI Bootstrap w wersji 0.12.1.

I został ostrzeżony do tego roztworu przez to .

Jason Swett
źródło
To znacznie lepsze rozwiązanie. Dużo czystsze. Niedawno zaktualizowaliśmy do wersji 0.12.1 i obecnie naprawiamy istotne zmiany, które wprowadziła. Mogę dodać to do listy. Dzięki!!
coblr
Akceptuję tę odpowiedź, ponieważ jest to obecna implementacja i będzie bardziej przydatna dla tych, którzy kończą tutaj, próbując sprawić, by wszystko działało. Przeczytaj cały wątek, chyba że używasz najnowszej (~ 0.12) wersji Angular UI.
coblr
Modal nie wydaje się być zamykany za pomocą $ modalStack, jeśli stan zmienił się, jeśli zakres jest ustawiony
phazei
Cześć, to rozwiązało mój problem na chwilę, ale zauważyłem dziwną rzecz podczas zamykania okna dialogowego / modalnego, zawartość się zmieniała i wydawało się, że coś zepsuło coś w obiekcie zasięgu. dodanie zakresu: $ scope, preserveScope: true // <- ważne jakoś pomogło! nie wiem dlaczego, ale znalazłem to na material.angularjs.org/latest/api/service/ ... Edycja: Dowiedziałem się dlaczego. kiedy ustawisz zakres: dla okna dialogowego, a następnie zamknij okno dialogowe „Ten zakres zostanie zniszczony po usunięciu dolnego arkusza, chyba że parametr preserveScope ma wartość true”.
Max
W moim kontrolerze używam vm = this. Nie używam $ scope. Co więc powinienem przypisać do zakresu?
Ankit Prajapati
66

W przypadku zasięgów zagnieżdżonych nie należy wiązać <input>s bezpośrednio z członkami zakresu:

<input ng-model="name" /> <!-- NO -->

Powiąż je przynajmniej o jeden poziom głębiej:

<input ng-model="form.name" /> <!-- YES -->

Powodem jest to, że zakresy prototypowo dziedziczą zakres nadrzędny. Dlatego podczas ustawiania elementów członkowskich pierwszego poziomu są one ustawiane bezpośrednio w zakresie podrzędnym, bez wpływu na rodzica. W przeciwieństwie do tego podczas tworzenia powiązania z zagnieżdżonymi polami ( form.name) element członkowski formjest odczytywany z zakresu nadrzędnego, więc dostęp do namewłaściwości uzyskuje dostęp do prawidłowego celu.

Przeczytaj bardziej szczegółowy opis tutaj .

Nikos Paraskevopoulos
źródło
14
Zmiana tego na „form.name” nic nie dała, ale zmiana na ng-model = „$ parent.name” rozwiązała problem. Dzięki! (i dziękuję również za materiały do ​​czytania. Jeszcze tego nie widziałem.)
coblr
1
Jeśli użyjesz controller asskładni, nie napotkasz problemów z zagnieżdżonym zakresem, takich jak ten
okradnij
Jaka jest controller as składnia?
adrianboimvaser
1
Zobacz docs.angularjs.org/api/ng.directive:ngController . Zasadniczo robi NG-controller = "MyCtrl jako mojego" następnie odwoływania się NG-modelu podobnego my.someVar
Ryan Q
2
@Nikos Paraskevopoulos, Co oznacza „form.name”? Nie ma o tym żadnej wzmianki w dostarczonym kodzie!
Łukasz Bachman
7

Aktualizacja listopad 2014 :

Właściwie twój kod powinien działać po aktualizacji do ui-bootstrap 0.12.0. Zakres transkludowany jest łączony z zakresem kontrolera, więc nie ma już potrzeby $parentani form.rzeczy.

Przed 0.12.0 :

Modal używa transkluzji, aby wstawić swoją zawartość. Dzięki temu ngFormmożesz kontrolować zakres według nameatrybutu. Aby wyjść z zakresu transkludowanego, wystarczy zmodyfikować formularz w ten sposób:

<form name="$parent">

lub

<form name="$parent.myFormData">

Dane modelu będą dostępne w zakresie kontrolera.

gertas
źródło
Aby było jasne, czy mówisz, że zakres kontrolera, wewnątrz którego dzwonisz, $modalpowinien być dostępny dla kontrolera przypisanego do modalu?
Jason Swett
Nie, problem polegał na tym, że nawet modalny kontroler instancji nie był łatwo dostępny dla formularzy. Aby uzyskać dostęp do kontrolera otwierającego modal, wystarczy wpisać scope:$scopemapę parametrów $ modal.open.
gertas
Masz na myśli Angular UI? Czy to różni się od UI Bootstrap?
Noah
1
$scope.open = function () {

          var modalInstance = $uibModal.open({
              animation: $scope.animationsEnabled,
              templateUrl: 'myModalContent.html',
              controller: 'salespersonReportController',
              //size: size
              scope: $scope
            });

      };

to działa dla mnie zakres: $ zakres dziękuję Jason Swett

ali Shoaib
źródło
1

Dodaję zakres: $ zakres, to działa .Cool

JBRandri
źródło