Sök…


Tvåvägs databindning slutar fungera

Man bör ha i åtanke att:

  1. Angular's databindning förlitar sig på Javascript prototyvliga arv, vilket är föremål för variabel skuggning .
  2. Ett barnomfång arv normalt prototypiskt från sitt föräldraområde. Ett undantag från denna regel är ett direktiv som har ett isolerat tillämpningsområde eftersom det inte ärotiskt prototypiskt.
  3. Det finns några direktiv som skapar ett nytt barnomfång: ng-repeat , ng-switch , ng-view , ng-if , ng-controller , ng-include , etc.

Detta innebär att när du försöker binda två data till en primitiv som finns inuti ett barnomfång (eller tvärtom), kanske saker inte fungerar som förväntat. Här är ett exempel på hur lätt det är att "bryta" AngularJS.

Det här problemet kan lätt undvikas genom att följa dessa steg:

  1. Ha en "." i din HTML-mall när du binder till data
  2. Använd controllerAs syntax eftersom det främjar användningen av bindning till ett "prickat" objekt
  3. $ förälder kan användas för att tillgång till moder scope variabler snarare än barn omfattning. som inuti ng-if vi kan använda ng-model="$parent.foo" ..

Ett alternativ för ovanstående är att binda ngModel till en getter / setter-funktion som kommer att uppdatera cache-versionen av modellen när den anropas med argument, eller returnera den när den anropas utan argument. För att kunna använda en getter / setter-funktion måste du lägga till ng-model-options="{ getterSetter: true }" till elementet med attributet ngModal och att ringa getter-funktionen om du vill visa dess värde i uttrycket ( Arbetande exempel ).

Exempel

Se:

<div ng-app="myApp" ng-controller="MainCtrl">
    <input type="text" ng-model="foo" ng-model-options="{ getterSetter: true }">
    <div ng-if="truthyValue">
        <!-- I'm a child scope (inside ng-if), but i'm synced with changes from the outside scope -->
        <input type="text" ng-model="foo">
    </div>
    <div>$scope.foo: {{ foo() }}</div>
</div>

Kontrollant:

angular.module('myApp', []).controller('MainCtrl', ['$scope', function($scope) {
    $scope.truthyValue = true;
      
    var _foo = 'hello'; // this will be used to cache/represent the value of the 'foo' model 
      
    $scope.foo = function(val) {
        // the function return the the internal '_foo' varibale when called with zero arguments,
        // and update the internal `_foo` when called with an argument
        return arguments.length ? (_foo = val) : _foo;
    };
}]);

Bästa praxis : Det är bäst att hålla getters snabbt eftersom Angular sannolikt kommer att ringa dem oftare än andra delar av din kod ( referens ).

Saker att göra när du använder html5Mode

När du använder html5Mode([mode]) är det nödvändigt att:

  1. Du anger bas-URL för applikationen med en <base href=""> i huvudet på ditt index.html .

  2. Det är viktigt att base tag kommer innan taggar med URL-förfrågningar. Annars kan detta resultera i det här felet - "Resource interpreted as stylesheet but transferred with MIME type text/html" . Till exempel:

    <head>
        <meta charset="utf-8">
        <title>Job Seeker</title>
    
        <base href="/">
    
        <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css" />
        <link rel="stylesheet" href="/styles/main.css">
    </head>
    
  3. Om du gör någon vill ange en base tag, configure $locationProvider till inte kräva en base tag genom att en definition objekt med requireBase:false till $locationProvider.html5Mode() så här:

    $locationProvider.html5Mode({
        enabled: true,
        requireBase: false
    });
    
  4. För att stödja direkt laddning av HTML5-URL: er måste du aktivera omskrivning av serversidan på URL-sidan. Från AngularJS / Developer Guide / Använda $ -plats

    Att använda det här läget kräver omskrivning av URL på serversidan, i princip måste du skriva om alla dina länkar till startpunkten för din applikation (t.ex. index.html ). Att kräva en <base> -tagg är också viktigt för det här fallet, eftersom det gör att Angular kan skilja mellan den del av webbadressen som är applikationsbasen och sökvägen som ska hanteras av applikationen.

    En utmärkt resurs för exempel på omskrivning av förfrågningar för olika HTTP-serverimplementeringar finns i ui-routerns vanliga frågor - Hur man gör: Konfigurera din server så att den fungerar med html5Mode . Till exempel Apache

     RewriteEngine on
    
     # Don't rewrite files or directories
     RewriteCond %{REQUEST_FILENAME} -f [OR]
     RewriteCond %{REQUEST_FILENAME} -d
     RewriteRule ^ - [L]
    
     # Rewrite everything else to index.html to allow html5 state links
     RewriteRule ^ index.html [L]
    

    nginx

     server {
         server_name my-app;
    
         root /path/to/app;
    
         location / {
             try_files $uri $uri/ /index.html;
         }
     }
    

    uttrycka

     var express = require('express');
     var app = express();
    
     app.use('/js', express.static(__dirname + '/js'));
     app.use('/dist', express.static(__dirname + '/../dist'));
     app.use('/css', express.static(__dirname + '/css'));
     app.use('/partials', express.static(__dirname + '/partials'));
    
     app.all('/*', function(req, res, next) {
         // Just send the index.html for other files to support HTML5Mode
         res.sendFile('index.html', { root: __dirname });
     });
    
     app.listen(3006); //the port you want to use
    

7 Deadly Sins of AngularJS

Nedan är listan över några misstag som utvecklare ofta gör under användning av AngularJS-funktioner, några lärdomar och lösningar på dem.

1. Manipulera DOM genom regulatorn

Det är lagligt, men måste undvikas. Controllers är platserna där du definierar dina beroenden, binder dina data till vyn och gör ytterligare affärslogik. Du kan tekniskt manipulera DOM i en controller, men när du behöver samma eller liknande manipulation i en annan del av din app, behöver du en annan controller. Så den bästa praxisen med detta tillvägagångssätt är att skapa ett direktiv som inkluderar alla manipulationer och använder direktivet i hela din app. Därför lämnar styrenheten vyn intakt och gör sitt jobb. I ett direktiv är kopplingsfunktion det bästa stället att manipulera DOM. Den har full tillgång till omfattningen och elementet, så genom att använda ett direktiv kan du också dra nytta av återanvändbarhet.

link: function($scope, element, attrs) {
    //The best place to manipulate DOM
}

Du kan komma åt DOM-element i bindningsfunktion genom flera sätt, såsom element parametern, angular.element() metoden, eller ren Java.

2. Databindande vid transkludering

AngularJS är berömd med sin tvåvägsdatabindning. Men du kan ibland stöta på att dina uppgifter endast är enkelriktade i direktiv. Stoppa där, AngularJS har inte fel men förmodligen du. Direktiv är lite farliga platser eftersom barnomfattning och isolerade omfattningar är inblandade. Antag att du har följande direktiv med en transkludering

<my-dir>
    <my-transclusion>
    </my-transclusion>
</my-dir>

Och inom my-transclusion har du några element som är bundna till uppgifterna i det yttre omfånget.

<my-dir>
    <my-transclusion>
        <input ng-model="name">
    </my-transclusion>
</my-dir>

Ovanstående kod fungerar inte korrekt. Här skapar transkludering ett barnomfång och du kan få namnvariabeln, rätt, men oavsett ändring du gör till denna variabel kommer att stanna kvar. Så du kan verkligen ansluta denna variabel till $ parent.name . Men användningen kanske inte är den bästa praxis. Ett bättre tillvägagångssätt skulle vara att slå in variablerna i ett objekt. Till exempel i kontrollenheten kan du skapa:

$scope.data = {
    name: 'someName'
}

Sedan i transkluderingen kan du komma åt denna variabel via 'data' -objektet och se att tvåvägsbindning fungerar perfekt!

<input ng-model="data.name">

Inte bara i slutsatser, utan i hela appen är det en bra idé att använda den prickade notationen.

3. Flera direktiv tillsammans

Det är faktiskt lagligt att använda två direktiv tillsammans inom samma element, så länge du följer regeln: två isolerade omfattningar kan inte existera på samma element. Generellt sett, när du skapar ett nytt anpassat direktiv, tilldelar du ett isolerat område för enkel parameteröverföring. Antagande att direktiven myDirA och myDirB har isolerade omfattningar och myDirC inte har, kommer följande element att vara giltigt:

<input my-dir-a my-dirc>

Följande element orsakar konsolfel:

<input my-dir-a my-dir-b>

Därför måste direktiv användas på ett klokt sätt med hänsyn till tillämpningsområdet.

4. Missbruk av $ emit

$ emit, $ broadcast och $ on, dessa fungerar i en avsändare-mottagare princip. Med andra ord är de ett kommunikationsmedel mellan kontrollerare. Till exempel avger följande rad "someEvent" från styrenhet A, som ska fångas av den berörda styrenheten B.

$scope.$emit('someEvent', args);

Och följande rad fångar "someEvent"

$scope.$on('someEvent', function(){});

Hittills verkar allt perfekt. Men kom ihåg att om styrenheten B inte åberopas ännu, kommer händelsen inte att fångas, vilket innebär att både emitter- och mottagarkontrollanter måste åberopas för att detta ska fungera. Så igen, om du inte är säker på att du definitivt måste använda $ emit, verkar bygga en tjänst ett bättre sätt.

5. Missbruk av $ räckvidd. $ Klocka

$ scope. $ watch används för att titta på en variabel förändring. När en variabel har ändrats åberopas denna metod. Ett vanligt misstag som gjorts är dock att ändra variabeln inom $ scope. $ Watch. Detta kommer att orsaka inkonsekvens och oändlig $ smältslinga vid någon tidpunkt.

$scope.$watch('myCtrl.myVariable', function(newVal) {
    this.myVariable++;
});

Så i ovanstående funktion, se till att du inte har några funktioner på myVariable och newVal.

6. Bindningsmetoder till vyer

Detta är en av de dödligaste synderna. AngularJS har tvåvägsbindning, och när något ändras uppdateras vyerna många gånger. Så om du binder en metod till ett attribut i en vy kan den metoden potentiellt kallas hundra gånger, vilket också gör dig galen under felsökning. Det finns emellertid bara några attribut som är byggda för metodbindning, såsom ng-klick, ng-oskärpa, ng-on-Change, etc, som förväntar sig metoder som paremeter. Antag till exempel att du har följande vy i din markering:

<input ng-disabled="myCtrl.isDisabled()" ng-model="myCtrl.name">

Här kontrollerar du inaktiverad status för vyn via metoden isDisabled. I styrenheten myCtrl har du:

vm.isDisabled = function(){
    if(someCondition)
        return true;
    else
        return false;
}

I teorin kan det tyckas vara korrekt men tekniskt sett kommer detta att orsaka en överbelastning, eftersom metoden kommer att köras otaliga gånger. För att lösa detta bör du binda en variabel. I din controller måste följande variabel existera:

vm.isDisabled

Du kan initiera denna variabel igen när aktiveringen av regulatorn

if(someCondition)
    vm.isDisabled = true
else
    vm.isDisabled = false

Om villkoret inte är stabilt kan du binda detta till en annan händelse. Då ska du binda denna variabel till vyn:

<input ng-disabled="myCtrl.isDisabled" ng-model="myCtrl.name">

Nu har alla attribut i vyn vad de förväntar sig och metoderna kommer att köras endast när det behövs.

7. Använder inte Angular funktioner

AngularJS ger mycket bekvämlighet med några av dess funktioner, inte bara förenklar din kod utan också gör den mer effektiv. Några av dessa funktioner listas nedan:

  1. vinkelformigt. För alla slingor (varning, du kan inte "bryta;" det, du kan bara förhindra att du kommer in i kroppen, så tänk på prestanda här.)
  2. angular.element för DOM-väljare
  3. angular.copy : Använd detta när du inte ska ändra huvudobjektet
  4. Formvalideringar är redan fantastiska. Använd smutsiga, orörda, berörda, giltiga, obligatoriska och så vidare.
  5. Förutom Chrome-felsökare kan du också använda felsökning för mobilutveckling.
  6. Och se till att du använder Batarang . Det är en gratis Chrome-förlängning där du enkelt kan inspektera omfattningar
  7. .


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow