2015-10-29 10 views
20

Ich habe zwei Bootstrap-Registerkarten auf einer Seite und jede Registerkarte zeigt eine Liste an. Ich möchte jedes Listenelement ein Quadrat und schrieb diese AngularJS Richtlinie, um die Höhe jedes Listenelement auf seiner Bootstrap kontrollierte dynamische Breite gleich sein:Warum funktioniert diese Width-AngularJS-Direktive nicht beim Wechseln der Bootstrap-Registerkarten?

app.directive('squareDiv', function() { 
    return { 
     restrict: "A", 
     link: function (scope, element,attr) { 
      scope.getWidth = function() { 
       return element.width(); 
      }; 
      scope.$watch(scope.getWidth, function (width) { 
       element.css({ 
        height: width + 'px' 
       }); 
      }, true); 
     } 
    }; 
}); 

Wenn ich diese Seite laden, die erste Registerkarte Listenelemente Als Quadrate erscheinen, was bedeutet, dass die Richtlinie funktioniert. Aber wenn ich auf eine andere Registerkarte klicke, haben die Listenelemente dort die Standardhöhe von 100 px. Wenn ich zurück zur ersten Registerkarte wechsle, haben jetzt auch die Listenelemente die Standardhöhe.

Was läuft hier falsch?

UPDATE 1:

hier die Verbindung zu einer Plunker, die dieses Problem veranschaulicht: http://plnkr.co/edit/Pc7keuRXR9R3U6AhZmFE?p=preview

UPDATE 2:

Plunker mit Bootstrap ersetzt durch die UI-Bootstrap, die immer noch das gleiche Problem hat: http://plnkr.co/edit/rLE1wUAHKzJP6FVnGF6b?p=preview

UPDATE 3:

Plunker mit Uhr für die anstelle Registerkarte Schalter der Breitenänderung (Workaround für das ursprüngliche Problem der Breitenuhr funktioniert nicht richtig; muss eine separate Direktive für die Anpassung an Breitenänderungen aufgrund von Fenstergrößenänderung verwenden): http://plnkr.co/edit/Y4Goe0cexq979JsIcBxl?p=preview

Ich würde immer noch gerne verstehen, warum die Weitenuhr nach einem Tabschalter nicht mehr ordnungsgemäß funktioniert.

+2

Es kann sein, weil die Reiter versteckt ist, so dass ihr Inhalt noch nicht Dimensionen haben. Wie auch immer, es würde helfen, wenn du einen Plunder machst oder so. –

+1

Das ist richtig, ein Plünderer könnte eine große Hilfe sein! –

+0

Hier ist der Link zu einem Plunker, der dieses Verhalten veranschaulicht: http://plnkr.co/edit/Pc7keuRXR9R3U6AhZmFE?p=preview Direktive funktioniert auf Tab 1, aber nicht auf Tab 2 – Price

Antwort

8

Der Beobachter Ihrer Anweisung ist ein Digest-Zyklus hinter dem, was passiert. Wenn Sie genau hinsehen, werden Sie feststellen, dass das erste Klicken auf die Registerkarte nicht viel bringt (nichts, was in der Konsole protokolliert wird). Was Sie sehen, ist, dass die Größe der Elemente Ihres aktiven Tabs auf die Höhen der verborgenen Tabs-Elemente angepasst wird. Die Höhe der ausgeblendeten Tabs ist also korrekt. Ich würde dringend die Verwendung der eckigen Version des Bootstraps anstelle des generischen empfehlen. Auf diese Weise wird alles (Ereignisse) von eckigen gesteuert.

https://angular-ui.github.io/bootstrap/

edit: dies vielleicht nützlich für die Verdauung Zyklus Verständnis Triggerung und Rückrufe außerhalb Winkel: http://school.codecraftpro.com/courses/angularjs-1x-fundamentals/lectures/392422

edit2: auch nützlich https://scotch.io/tutorials/how-to-correctly-use-bootstrapjs-and-angularjs-together

+0

Danke! Ich dachte, Angular wäre mit dem Standard-Bootstrap kompatibel. Wie konnten Sie feststellen, dass der Beobachter einen Verdauungszyklus hinter sich hat? – Price

+1

Bei Pagerload sehen Sie 4-4 Konsolenprotokolle. Nach dem Klicken auf Tab 2 gibt es nichts. Dann kommt es wieder zurück. Das liegt hauptsächlich daran, dass Bootstrap js click nicht innerhalb von angular registriert wird. Einpacken in eine Direktive kann das lösen, aber da die eckigen Jungs das schon gemacht haben, könntest du etwas Zeit verschwenden :) – dekztah

+1

Korrektur: nicht in diesem Digest-Zyklus registriert, aber einen Zyklus später – dekztah

0

Wir wissen, dass die Spaltung von Bootstrap-Tabs Das Schalten ist der Breite deiner Divs voraus. Anstatt die Breite Ihrer divs zu ändern, sehen wir uns stattdessen an, wann sich Ihr Tab ändert. Wenn sich die Registerkarte ändert, warten wir 1 ms, um sicherzustellen, dass wir uns im nächsten Digest-Zyklus befinden. Dann holen Sie sich die Breite und aktualisieren Sie Ihre Schachtelhöhe.

Ich habe keine Ahnung, warum das der Fall ist, aber hier ist die Lösung, die funktioniert.

Hier ist ein plunker example

Javascript

var app = angular.module("app",['ngAnimate', 'ui.bootstrap']); 
app.controller('mainController',['$scope',function($scope){ 
    $scope.tabs = [ 
     {'title': 'Tab 1'}, 
     {'title': 'Tab 2'} 
    ]; 
}]); 

app.directive('squareDiv', function ($timeout) { 
    return { 
     restrict: "A", 
     link: function (scope, element, attr) { 

      scope.active = function() { 
       return scope.tabs.filter(function(tab){ 
        return tab.active; 
       })[0]; 
      }; 

      scope.$watch(scope.active, function (tabActive) { 
       $timeout(function() { 
        element.css({ 
         height: element.width() 
        }); 
       }, 1); 

      }); 

     } 
    } 
}); 
+0

Danke! Pro Kommentar zu der anderen Antwort müssten wir den Verweis auf ngAnimate entfernen, um zu verhindern, dass die Tabs ein paar Mal umgestellt werden, um die Höhen in dieser Lösung durcheinander zu bringen. – Price

+0

eigentlich, wenn Sie auch requestAnimationFrame innerhalb der $ Timeout, das Layout Thrashing verhindern würde, und Sie könnten nganimate beibehalten. siehe: http://wilsonpage.co.uk/preventing-layout-thrashing/ – dekztah

+0

Sehr interessant! Ich habe gerade den Plunker aktualisiert - http://plnkr.co/edit/UyxNI9gsOyBg6sNdcvYs?p=preview - um requestAnimationFrame zu verwenden und es scheint zu funktionieren. Auch das andere große Problem scheint zu sein, was @ExpertSystem brachte, dass jQuery die Breite von 100% zu 100px konvertiert, was auch nicht gut sein kann. – jjbskir

Verwandte Themen