O ng-model do Angularjs não funciona dentro do ng-if

206

Aqui está o violino mostrando o problema. http://jsfiddle.net/Erk4V/1/

Parece que se eu tiver um modelo ng dentro de um ng-if, o modelo não funcionará conforme o esperado.

Gostaria de saber se isso é um bug ou se estou entendendo mal o uso adequado.

<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
fonte
6
Para uma solução alternativa, você pode usar ng-show = "CONDITION" em vez de ng-if. Deveria funcionar.
Hari Das
Presumo que isso não é mais um problema agora que se pode usar controllerAs?
21716 Jamiebarrow
Eu tive o mesmo problema ao usar uma directiva com implícita scope:falsee acrescentei ng-ifelemento em torno da directiva - os âmbitos eram obrigados inicialmente, mas eles se separaram depois de um observador atualizadas um dos valores de escopo ...
Aprillion

Respostas:

223

A ng-ifdiretiva, como outras diretivas, cria um escopo filho. Veja o script abaixo (ou 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>

Portanto, sua caixa de seleção altera o testbinterior do escopo filho, mas não o escopo pai externo.

Observe que, se você quiser modificar os dados no escopo pai, precisará modificar as propriedades internas de um objeto, como na última div que eu adicionei.

Jon7
fonte
1
Como eu acessaria o escopo do ng-if a partir da função dos controladores principais? Um pouco frustrante. Qual o motivo disso?
23813 Justin Carson
Deixa pra lá, @sza acabou de responder a essa pergunta. Vou marcar esta resposta como correta, pois explica o motivo exato pelo qual eu estava tendo problemas.
Justin Carlson
21
Esse é um dos motivos pelos quais é bastante comum usar um objeto que contenha seu escopo, em vez de modificar diretamente as propriedades do escopo, como apontado no exemplo: $scope.obj = {...}e ng-model="obj.someProperty"supera essa limitação.
Wulftone 22/10
204

Você pode usar $parentpara se referir ao modelo definido no escopo pai como este

<input type="checkbox" ng-model="$parent.testb" />
zs2020
fonte
16
então eu tenho ng-model="$parent.$parent.fooporque eu já estou dentro de um escopo com um ng-repeat- este é realmente o melhor caminho?
Chovy
4
isso é realmente confuso. por que é que? e por que o ng-hide não tem escopo próprio?
Dominik Goltermann 03/03
5
Re @Gaul: presumivelmente porque ng-hide / ng-show opera no DOM atual e apenas adicione / remova uma classe CSS, enquanto ng-if / ng-switch / ng-repeat todo o lixo com o DOM e acompanhe o estado extra . Parece sensato.
trisweb
4
Sensível não é a palavra que eu uso.
Jonathan Dumaine
3
Adicione um objeto ao escopo original e altere as propriedades desse objeto. por exemplo, ng-model = "myObject.property". Isso contornará toda a escopo / $ inanity pai. Google "regra de ponto angular" para mais informações.
Asmor 16/02
50

Você pode usar a diretiva ngHide (ou ngShow) . Não cria escopo filho como ngIf.

<div ng-hide="testa">
Vasiliy Kevroletin
fonte
3
Por que, ngIfentão, cria um escopo filho? Parece muito estranho para mim.
freeall
5
Preste atenção aos comentários da resposta zsong. ng-hidenão altera a estrutura html. Simplesmente muda os estilos de CSS. ng-ifé mais complexo: remove e insere peças html, dependendo da condição. Ele cria o escopo filho para armazenar o estado (pelo menos deve armazenar parte html oculta).
Vasiliy Kevroletin
Sim, trabalhe para mim
Basit 02/04
7

Tivemos isso em muitos outros casos, o que decidimos internamente é sempre ter um wrapper para a diretiva / controlador, para que não precisemos pensar sobre isso. Aqui está seu exemplo com nosso invólucro.

<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>

Espera que isso ajude, Yishay

Yishay Haspel
fonte
3

Sim, a diretiva ng-hide (ou ng-show) não criará escopo filho.

Aqui está a minha prática:

<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
fonte
0

Você pode fazer assim e sua função mod funcionará perfeitamente, deixe-me saber se você quer uma caneta 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
fonte