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.


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 .


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 .


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.


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


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.