Angularjs ng-model no funciona dentro de ng-if

206

Aquí está el violín que muestra el problema. http://jsfiddle.net/Erk4V/1/

Parece que si tengo un modelo ng dentro de un ng-if, el modelo no funciona como se esperaba.

Me pregunto si esto es un error o si estoy malinterpretando el uso adecuado.

<div ng-app >
    <div ng-controller="main">

        Test A: {{testa}}<br />
        Test B: {{testb}}<br />
        Test C: {{testc}}<br />

        <div>
            testa (without ng-if): <input type="checkbox" ng-model="testa" />
        </div>
        <div ng-if="!testa">
            testb (with ng-if): <input type="checkbox" ng-model="testb" />
        </div>
        <div ng-if="!someothervar">
            testc (with ng-if): <input type="checkbox" ng-model="testc" />
        </div>

    </div>
</div>
Justin Carlson
fuente
66
Para una solución alternativa, puede usar ng-show = "CONDITION" en lugar de ng-if. Deberia de funcionar.
Hari Das
¿Supongo que esto ya no es un problema ahora que uno puede usar controllerAs?
jamiebarrow
Tuve el mismo problema al usar una directiva implícita scope:falsey agregué ng-ifelementos alrededor de la directiva: los ámbitos se vincularon inicialmente, pero se separaron después de que un observador actualizó uno de los valores de alcance ...
Aprillion

Respuestas:

223

La ng-ifdirectiva, como otras directivas, crea un ámbito secundario. Vea el script a continuación (o este jsfiddle )

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular.min.js"></script>

<script>
    function main($scope) {
        $scope.testa = false;
        $scope.testb = false;
        $scope.testc = false;
        $scope.obj = {test: false};
    }
</script>

<div ng-app >
    <div ng-controller="main">
        
        Test A: {{testa}}<br />
        Test B: {{testb}}<br />
        Test C: {{testc}}<br />
        {{obj.test}}
        
        <div>
            testa (without ng-if): <input type="checkbox" ng-model="testa" />
        </div>
        <div ng-if="!testa">
            testb (with ng-if): <input type="checkbox" ng-model="testb" /> {{testb}}
        </div>
        <div ng-if="!someothervar">
            testc (with ng-if): <input type="checkbox" ng-model="testc" />
        </div>
        <div ng-if="!someothervar">
            object (with ng-if): <input type="checkbox" ng-model="obj.test" />
        </div>
        
    </div>
</div>

Por lo tanto, su casilla de verificación cambia el testbinterior del ámbito secundario, pero no el ámbito primario externo.

Tenga en cuenta que si desea modificar los datos en el ámbito primario, deberá modificar las propiedades internas de un objeto como en el último div que agregué.

Jon7
fuente
1
¿Cómo accedería al alcance de ng-if desde la función de los controladores principales? Un poco frustrante ¿Cuál es la razón de esto?
Justin Carlson
No importa, @sza acaba de responder esa ^ pregunta. Sin embargo, voy a marcar esta respuesta como correcta, ya que explica la razón exacta por la que estaba teniendo problemas.
Justin Carlson
21
Esta es una razón por la que es bastante común usar un objeto contenedor en su alcance, en lugar de modificar las propiedades del alcance directamente, como se señala en el ejemplo: $scope.obj = {...}y ng-model="obj.someProperty"supera esta limitación.
wulftone
204

Puede usar $parentpara referirse al modelo definido en el ámbito principal como este

<input type="checkbox" ng-model="$parent.testb" />
zs2020
fuente
16
entonces lo tengo ng-model="$parent.$parent.fooporque ya estoy dentro de un alcance con un ng-repeat- ¿es esta realmente la mejor manera?
chovy
44
Esto realmente es confuso. ¿porqué es eso? ¿Y por qué ng-hide no tiene su propio alcance?
Dominik Goltermann
55
Re @Gaul: presumiblemente porque ng-hide / ng-show opera en el DOM actual y simplemente agrega / elimina una clase CSS, mientras que ng-if / ng-switch / ng-repite toda la suciedad con el DOM y realiza un seguimiento del estado adicional . Parece sensato
trisweb
44
Sensible no es la palabra que uso.
Jonathan Dumaine
3
Agregue un objeto al ámbito original y cambie las propiedades de ese objeto. por ejemplo, ng-model = "myObject.property". Esto evitará todo el alcance / $ parent inanity. Google "regla de punto angular" para más información.
Asmor
50

Puede usar la directiva ngHide (o ngShow) . No crea el ámbito secundario como lo hace ngIf.

<div ng-hide="testa">
Vasiliy Kevroletin
fuente
3
¿Por qué ngIfentonces crea un ámbito secundario? Me parece muy extraño.
freeall
55
Presta atención a los comentarios de la respuesta zsong. ng-hideno cambia la estructura html. Simplemente cambia los estilos CSS. ng-ifes más complejo: elimina e inserta partes html según la condición. Crea un ámbito secundario para almacenar el estado (al menos debe almacenar la parte oculta html).
Vasiliy Kevroletin
Sí, trabaja para mí
Basit
7

Tuvimos esto en muchos otros casos, lo que decidimos internamente es tener siempre un contenedor para el controlador / directiva para que no necesitemos pensarlo. Aquí está su ejemplo con nuestro contenedor.

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular.min.js"></script>

<script>
    function main($scope) {
        $scope.thisScope = $scope;
        $scope.testa = false;
        $scope.testb = false;
        $scope.testc = false;
        $scope.testd = false;
    }
</script>

<div ng-app >
    <div ng-controller="main">

        Test A: {{testa}}<br />
        Test B: {{testb}}<br />
        Test C: {{testc}}<br />
        Test D: {{testd}}<br />

        <div>
            testa (without ng-if): <input type="checkbox" ng-model="thisScope.testa" />
        </div>
        <div ng-if="!testa">
            testb (with ng-if): <input type="checkbox" ng-model="thisScope.testb" />
        </div>
        <div ng-show="!testa">
            testc (with ng-show): <input type="checkbox" ng-model="thisScope.testc" />
        </div>
        <div ng-hide="testa">
            testd (with ng-hide): <input type="checkbox" ng-model="thisScope.testd" />
        </div>

    </div>
</div>

Espero que esto ayude, Yishay

Yishay Haspel
fuente
3

Sí, la directiva ng-hide (o ng-show) no creará un ámbito secundario.

Aquí está mi práctica:

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.0rc1/angular.min.js"></script>

<script>
    function main($scope) {
        $scope.testa = false;
        $scope.testb = false;
        $scope.testc = false;
        $scope.testd = false;
    }
</script>

<div ng-app >
    <div ng-controller="main">

        Test A: {{testa}}<br />
        Test B: {{testb}}<br />
        Test C: {{testc}}<br />
        Test D: {{testd}}<br />

        <div>
            testa (without ng-if): <input type="checkbox" ng-model="testa" />
        </div>
        <div ng-if="!testa">
            testb (with ng-if): <input type="checkbox" ng-model="$parent.testb" />
        </div>
        <div ng-show="!testa">
            testc (with ng-show): <input type="checkbox" ng-model="testc" />
        </div>
        <div ng-hide="testa">
            testd (with ng-hide): <input type="checkbox" ng-model="testd" />
        </div>

    </div>
</div>

http://jsfiddle.net/bn64Lrzu/

Xiayan Y
fuente
0

Puedes hacerlo así y tu función de mod funcionará perfectamente, avísame si quieres un bolígrafo de código

  <div ng-repeat="icon in icons">                   
                <div class="row" ng-if="$index % 3 == 0 ">
                    <i class="col col-33 {{icons[$index + n].icon}} custom-icon"></i>
                    <i class="col col-33 {{icons[$index + n + 1].icon}} custom-icon"></i>
                    <i class="col col-33 {{icons[$index + n + 2].icon}} custom-icon"></i>
                </div>
         </div>
Xvegas
fuente