2012-05-30 4 views
12

Wie kann ich ein Anker-Tag mit dieser benutzerdefinierten Bindung deaktivieren und aktivieren. Es funktioniert hervorragend mit Eingabeelementen, aber das Anchor-Tag ändert nur das CSS, nicht das Deaktivieren.knockout.js und Deaktivieren von Anchor-Tag

<a href="link" data-bind="myDisabled: !enabled()"/> 

ko.bindingHandlers.myDisabled = { 
    update: function(element, valueAccessor) { 
     var value = ko.utils.unwrapObservable(valueAccessor()); 
     ko.bindingHandlers.css.update(element, function() {return { disabled: value }; }); 
     ko.bindingHandlers.disable.update(element, valueAccessor); 
    } 
}; 
+0

Ich habe nur durch das Setzen ihrer onlick Anker-Tags "disabled" zu sehen falsch. Was meinst du mit dem Anker passieren, um es zu "deaktivieren"? – Tyrsius

+0

Nur um sicherzustellen, dass keine Klickereignisse ausgelöst werden. Wenn diese Option aktiviert ist, werden die Klickereignisse wieder aktiviert. –

+1

Als Alternative können Sie die KO-Kommentarlogik verwenden, um nur ein anderes Tag zu erzeugen. Siehe: http://stackoverflow.com/q/15969045/52551 –

Antwort

11

Sie müssen in Ihrem Bindungshandler ein Klickereignis erfassen.

HTML:

<a href="link" data-bind="disableClick: !enabled()">test</a> 
<br/><br/><br/> 
<input type="checkbox" data-bind="checked: enabled"> enabled ​ 

JavaScript:

ko.bindingHandlers.disableClick = { 
    init: function (element, valueAccessor) { 

     $(element).click(function(evt) { 
      if(valueAccessor()) 
       evt.preventDefault(); 
     }); 

    }, 

    update: function(element, valueAccessor) {   
     var value = ko.utils.unwrapObservable(valueAccessor()); 
     ko.bindingHandlers.css.update(element, function() {return { disabled_anchor: value }; }); 
    } 
}; 

ko.applyBindings({ enabled: ko.observable(false)}); 

Hier ist ein funktionierendes Beispiel:

http://jsfiddle.net/kp74u/54/

UPDATE 1: Wenn Sie andere Event-Handler nach Knockout-Bindung Handler gebunden müssen verhindern, wurde angebracht, müssen Sie stopImmediatePropagation an den Ereignishandler hinzuzufügen, zusammen mit preventDefault.

Beispiel: http://jsfiddle.net/kp74u/55/

UPDATE 2: Wenn Sie alle Event-Handler deaktivieren wollen (zusammen mit Click-Ereignishandler vor Ihrer verbindlichen Handler angebracht, Sie müssen zu 'hacken' die jquery Ereignisse Array). Bitte beachten Sie, dass diese nicht auf andere Versionen von jQuery arbeiten kann (Beispiel verwendet 1.7):

ko.bindingHandlers.disableClick = { 
    init: function(element, valueAccessor) { 

     $(element).click(function(evt) { 
      alert('test before'); 
     }); 

     $(element).click(function(evt) { 
      if (valueAccessor()) { 
       evt.preventDefault(); 
       evt.stopImmediatePropagation(); 
      } 
     }); 

     //begin of 'hack' to move our 'disable' event handler to top of the stack 
     var events = $.data(element, "events"); 
     console.log(events); 
     var handlers = events['click']; 

     if (handlers.length == 1) { 
      return; 
     } 

     handlers.splice(0, 0, handlers.pop()); 
     //end of 'hack' to move our 'disable' event handler to top of the stack 


     $(element).click(function(evt) { 
      alert('test after'); 
     }); 
    }, 

    update: function(element, valueAccessor) { 
     var value = ko.utils.unwrapObservable(valueAccessor()); 
     ko.bindingHandlers.css.update(element, function() { 
      return { 
       disabled_anchor: value 
      }; 
     }); 
    } 
}; 

Beispiel: http://jsfiddle.net/nickolsky/kp74u/40/

UPDATE 3: Wie erwähnt wurde (suggested edit by FIR55TORM, leider nicht genehmigen kann vollständig korrekt bearbeiten, weil ich bin zu spät zu überprüfen): wenn Sie jQuery 1.10.x verwenden, benötigen Sie einen Unterstrich hinzufügen, um das Objekt ‚Daten‘ zugreifen wie so:

var events = $._data(element, "events"); 

Revised Geige für jQuery 1.10.x: http://jsfiddle.net/nickolsky/kp74u/41/

+0

Hält dies andere Klickereignisse an? http://jsfiddle.net/kp74u/3/ –

+0

Ich habe ein Update zum Deaktivieren aller Klickereignisse hinzugefügt. – Artem

+0

Ab jQuery 1.8 können Sie nicht mehr über diese API auf die Daten zugreifen. Ersetzen durch 'jQuery._data (Schlüssel, Wert)' –

1

ich diese Antwort gefunden, wenn dies für eine Art und Weise zu tun, glotzen, aber ich wusste nicht, wie die Annäherung so meine eigene tat

var orgClickInit = ko.bindingHandlers.click.init; 
ko.bindingHandlers.click.init = function (element, valueAccessor, allBindingsAccessor, viewModel) { 
    if (element.tagName === "A" && allBindingsAccessor().enable != null) { 
     var disabled = ko.computed(function() { 
      return ko.utils.unwrapObservable(allBindingsAccessor().enable) === false; 
     }); 
     ko.applyBindingsToNode(element, { css: { disabled: disabled} }); 
     var handler = valueAccessor(); 
     valueAccessor = function() { 
      return function() { 
       if (ko.utils.unwrapObservable(allBindingsAccessor().enable)) { 
        handler.apply(this, arguments); 
       } 
      } 
     }; 

    } 
    orgClickInit(element, valueAccessor, allBindingsAccessor, viewModel); 
}; 

Seine nahtlos mit dem nativen Klick und ermöglicht eine Bindung (deaktivieren Bindung nicht implementiert) Fiddle (Fiddle auch meine Konvention über Konfiguration Bibliothek verwendet) http://jsfiddle.net/xCfQC/30/

+0

Wirklich mochte diese Idee, der Hauptnachteil ist, dass Sie eine "Klicken" Methode definieren müssen, damit es funktioniert. Siehe meine Antwort für eine Lösung, wo es mit oder ohne Klick funktioniert. – Edyn

0

mit @Anders als Inspiration zu beantworten, kam ich mit meiner eigenen Version dieses nach oben. Ermöglicht die Verwendung von "Aktivieren", "Deaktivieren" mit oder ohne "Klicken". Ermöglicht auch eine benutzerdefinierte deaktivierte Klasse, ansonsten wird standardmäßig "deaktiviert" angezeigt.

var koEnableUpdateOrig = ko.bindingHandlers.enable.update; 
ko.bindingHandlers.enable.update = function (element, valueAccessor, allBindings) { 
    // call original enable update 
    var result = koEnableUpdateOrig.apply(this, arguments); 
    var enabled = ko.unwrap(valueAccessor()); 

    // get and apply disabled class 
    var disabledClass = "disabled"; 
    if (allBindings) 
     disabledClass = allBindings().disabledClass || "disabled"; 
    if (enabled) { 
     $(element).removeClass(disabledClass); 
     if (element.tagName === "A") 
      $(element).off("click.koEnableUpdate"); 
    } 
    else { 
     $(element).addClass(disabledClass); 
     if (element.tagName === "A") 
      $(element).on("click.koEnableUpdate", function (e) { e.preventDefault(); }); 
    } 

    return result; 
}; 
ko.bindingHandlers.disable.update = function (element, valueAccessor, allBindings) { 
    // call enable with the reverse value 
    // the original knockout disable does this, but does not pass the allBindings 
    ko.bindingHandlers.enable.update(element, function() { 
     return !ko.unwrap(valueAccessor()) 
    }, allBindings); 
}; 

var koClickInitOrig = ko.bindingHandlers.click.init; 
ko.bindingHandlers.click.init = function (element, valueAccessor, allBindings) { 
    // wrap click function with enable/disable check 
    var valueAccessorOrig = valueAccessor(); 
    valueAccessor = function() { 
     return function() { 
      if (ko.unwrap(allBindings().enable) || 
       (allBindings().disable == null || !ko.unwrap(allBindings().disable))) { 
       valueAccessorOrig.apply(this, arguments); 
      } 
     } 
    }; 

    // apply wrapped click to original click init 
    koClickInitOrig.apply(this, arguments); 
}; 
+0

Kann wirklich den Usecase sehen, wenn Sie aktivieren/deaktivieren ohne einen Click-Handler: D Hier ist eine Version unterstützt deaktivieren http://jsfiddle.net/xCfQC/31/ – Anders

+1

@Anders Wenn Sie einen Anker mit einem Satz href und no haben Notwendigkeit für Klick. Das war meine Situation. – Edyn

+0

Aber die href wird immer noch ausgeführt, es ist nur CSS? Sie müssen false aus dem Click-Handler zurückgeben, damit es nicht ausgelöst wird. Sie könnten das in Ihrem Wrapper-Clikc-Handler beheben. – Anders

0

Das ist mein Ansatz:

JavaScript

(function() { 
    var originalDisableUpdate = ko.bindingHandlers.disable.update; 

    ko.bindingHandlers.disable.update = function (element, valueAccessor) { 
     if (element.tagName === 'A') { 
     var 
      value = ko.utils.unwrapObservable(valueAccessor()), 
      disabled = 'disabled'; 

     if (value) { 
      element.setAttribute(disabled, null); 
     } 
     else { 
      element.removeAttribute(disabled); 
     } 
     } 
     else { 
     originalDisableUpdate(element, valueAccessor); 
     } 
    }; 
})(); 

CSS

a[disabled] { 
    pointer-events:none; 
    cursor:default; 
}