2015-04-04 2 views
5

Mit AngularJS, zeige ich eine 2-Level-Liste wie dieseWie finde ich heraus, ob etwas in einem bestimmten div Fokus hat?

- first main item 
    - first subitem of the first main item 
    - second subitem of the first main item 
    - AN EMPTY ITEM AS PLACEHOLDER TO ENTER THE NEXT SUBITEM 
- second main item 
    - first subitem of the second main item 
    - second subitem of the second main item 
    - AN EMPTY ITEM AS PLACEHOLDER TO ENTER THE NEXT SUBITEM 

Um Platz zu sparen, ich möchte nur den Platzhalter zeigen, wenn etwas in den entsprechenden div Fokus hat, so dass es nur ein solcher Platzhalter. Ich weiß, dass es ngFocus gibt, aber ich würde etwas einfacheres vorziehen, als Tonnen von Event-Handlern zu erstellen. Vielleicht so etwas wie folgt aus:

<div ng-focus-model="mainItem.hasFocus" ng-repeat="mainItem in list"> 
    ... main item line 
    ... all subitems 
</div> 

Eine unidirektionale Bindung ausreichend sein würde, wie ich den Fokus nicht einstellen müssen.

+0

haben Sie eine Code? z.B. Jfiddle, Jsbin. Ich denke ich verstehe deinen Standpunkt, aber ... –

+0

Wir sind nicht klar, was genau du willst, könntest du bitte Geige/Plunkr hinzufügen? –

+0

@pankajparkar Vielleicht bin ich auch nicht. Also versuchte ich [ein Plunk] (http://plnkr.co/edit/EV9hwaf0W18BbZX1zQkJ?p=preview). Der auskommentierte wie ist der wichtige. – maaartinus

Antwort

7

Das Problem hier ist das Folgende; Wir möchten vermeiden, dass jedem Kind ein Ereignis-Listener hinzugefügt wird, sondern nur dem übergeordneten Element. Der Elternteil ist dafür verantwortlich, die entsprechenden Maßnahmen zu ergreifen. Die allgemeine Lösung hierfür ist die Verwendung einer gleichmäßigen Propagierung (Delegierung). Wir fügen nur einen Listener an das übergeordnete Element an, wenn ein Ereignis auf dem untergeordneten Element auftritt (in diesem Beispiel auf das Eingabeelement konzentrieren), wird es zum übergeordneten Element und das übergeordnete Element führt den Listener aus.

Hier ist die Richtlinie:

app.directive('ngFocusModel', function() { 
    return function (scope, element) { 

     var focusListener = function() { 
      scope.hasFocus = true; 
      scope.$digest(); 
     }; 

     var blurListener = function() { 
      scope.hasFocus = false; 
      scope.$digest(); 
     }; 


     element[0].addEventListener('focus', focusListener, true); 
     element[0].addEventListener('blur', blurListener, true); 
    }; 
}); 

Die Richtlinie für Veranstaltungen zuhört und setzt dementsprechend den Wert auf Umfang, so können wir bedingte Änderungen vornehmen.

Hier sind einige Dinge zu beachten.

focus und blur Ereignisse nicht "Blase", müssen wir "Ereigniserfassung" verwenden, um sie zu fangen. Deshalb wird element.on('focus/blur') nicht verwendet (es erlaubt nicht Capture, afaik), sondern eine addEventListener Methode. Mit dieser Methode können Sie angeben, ob der Listener bei "Event-Bubbling" oder "Event-Capturing" ausgeführt werden soll, indem Sie das dritte Argument entsprechend auf false oder true setzen. die „Blase“ verwendet, leider sind diese nicht in Firefox unterstützt (focusin und focusout)

Wir focusin und focusout Ereignisse haben könnte.

Hier ist ein plunker mit der Implementierung.

Update: Es fiel mir ein, dass dies mit reinem CSS mit der :focus Pseudo-Klasse durchgeführt werden kann, ist der einzige Nachteil, dass der Platzhalter in der richtigen Position sein muss (Geschwister) in Bezug auf die Eingabeelemente. Siehe codepen.

+0

Eine Sache zu beachten, Ereigniserfassung funktioniert nur auf IE9 + – SKYWALKR

+0

@SKYWALKR Und weder angularjs 1.3, so ist mir egal. Es funktioniert auf meinem alten Firefox und Chrome, also ist es in Ordnung. Vielen Dank für die Informationen. – maaartinus

+0

Die reine CSS-Lösung würde bei mir nicht funktionieren. Das "Event Capturing" klingt gut. Gibt es keine Aufräumarbeiten, wenn das Element weg ist? – maaartinus

2

Leider ist die einzige solide Methode, um zu tun, was Sie wollen, ist auf die Fokus \ Unschärfe-Ereignisse auf den Eingaben reagieren ... das ist die einzige Möglichkeit, benachrichtigt zu werden.

Sie könnten eine verborgene Eingabe als erstes Element in jedem div einfügen und das NgFocus-Attribut darauf setzen, aber das funktioniert nur, wenn ein Benutzer es eingibt.

2

DEMO

Ich habe eine kleine Richtlinie, die für das, was Sie benötigen, verwendet werden können:

app.directive('childFocus', function($window){ 

    var registered = []; 

    // observing focus events in single place 
    $window.addEventListener('focus', function(event){ 
    registered.forEach(function(element){ 
     if(element.contains(event.target)){ 
     // if element with focus is a descendant of the 
     // element with our directive then action is triggered 
     element._scope.$apply(element._scope.action); 
     } 
    }); 
    }, true) 

    return { 
    scope : { 
     action : '&childFocus' // you can pass whatever expression here 
    }, 
    link : function(scope, element){ 

     // keep track ref to scope object 
     element[0]._scope = scope; 

     // (probably better would be to register 
     // scope with attached element) 
     registered.push(element[0]); 

     scope.$on('destroy', function(){ 
     registered.splice(registered.indexOf(element[0]),1); 
     }); 
    } 
    } 
}); 
0

Sie konnten die focus Ereignis des '.parent *' Selektor verwenden, um alle Fokus-Ereignisse zu erfassen, dann Schleife durch jede des übergeordneten Elements DIV s und verwenden Sie den JQuery-Selektor :focus, um nach untergeordneten Elementen mit Fokus zu suchen, fügen Sie dann eine Klasse zum übergeordneten Element DIV hinzu und verwenden Sie diese Klasse zum Ein-/Ausblenden des Plocholders (see this jsfiddle):

$(function(){ 
 
    $('.parent *').focus(function(){ 
 
     $('.selected').removeClass('selected'); 
 
     $('.parent').each(function(index, el){ 
 
      (function($el){ 
 
       setTimeout(function(){ 
 
        console.log($el.attr('id')); 
 
        if($el.find(':focus').length){ 
 
         $el.addClass('selected'); 
 
        }  
 
       }); 
 
      })($(el)); 
 
     }); 
 
    }); 
 
});
.parent{ 
 
    padding:1rem; 
 
    margin:1rem; 
 
    border:solid 1px green; 
 
} 
 
.selected{ 
 
    border:solid 1px red; 
 
} 
 
.parent .placeholder{ 
 
    display:none; 
 
} 
 
.parent.selected .placeholder{ 
 
    display:block; 
 
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> 
 
<div class='parent' id='div1'> 
 
    <input type="text" /> 
 
    <div class='placeholder'>Placeholder</div> 
 
</div> 
 
<div class='parent' id='div2'> 
 
    <input type="text" /> 
 
    <div class='placeholder'>Placeholder</div> 
 
</div> 
 
<div class='parent' id='div3'> 
 
    <input type="text" /> 
 
    <div class='placeholder'>Placeholder</div> 
 
</div> 
 
<div class='parent' id='div4'> 
 
    <input type="text" /> 
 
    <div class='placeholder'>Placeholder</div> 
 
</div>