Jak programowo wywołać zdarzenie onclick () ze znacznika kotwicy, zachowując odwołanie „this” w funkcji onclick?

83

Poniższe nie działa ... (przynajmniej nie w Firefoksie: document.getElementById('linkid').click()nie jest funkcją)

<script type="text/javascript">
    function doOnClick() {
        document.getElementById('linkid').click();
        //Should alert('/testlocation');
    }
</script>
<a id="linkid" href="/testlocation" onclick="alert(this.href);">Testlink</a>
Ropstah
źródło

Odpowiedzi:

110

Potrzebujesz applyobsługi zdarzenia w kontekście tego elementu:

var elem = document.getElementById("linkid");
if (typeof elem.onclick == "function") {
    elem.onclick.apply(elem);
}

W przeciwnym razie thisodwołałoby się do kontekstu, w którym powyższy kod jest wykonywany.

Gumbo
źródło
3
Myślę, że jesteś jedyną osobą, która nie postrzega mnie jako głupka (nie wspominając o notacji nawiasów / niezgodności przeglądarki onclick | click). Na miejscu!
Ropstah
3
rozważ to: howtocreate.co.uk/tutorials/javascript/domevents - czy wywołanie funkcji onclick wywoła wszystkie zarejestrowane programy obsługi zdarzeń? Ponadto fałszywe wywołanie zdarzenia nie spowoduje wykonania domyślnej akcji skojarzonej z tym zdarzeniem (np. Przesłanie formularza).
jrharshath
Gumbo, ponieważ ten kod daje -różne- wyniki, nadal nie działa z bibliotekami Microsoft.Ajax i Microsoft.AjaxMvc ....
Ropstah
1
Dlaczego warto apply()tu używać ? Możesz po prostu to zrobić elem.onclick();i elembędzie to odniesienie „this” w funkcji - proste!
Doin
19

Najlepszym sposobem rozwiązania tego problemu jest użycie Vanilla JS, ale jeśli już używasz jQuery, istnieje bardzo proste rozwiązanie:

<script type="text/javascript">
    function doOnClick() {
        $('#linkid').click();
    }
</script>
<a id="linkid" href="/testlocation" onclick="alert(this.href);">Testlink</a>

Przetestowano w IE8-10, Chrome, Firefox.

luschn
źródło
3
dlaczego głos przeciw? skomentuj powód, abym mógł poprawić moje pytanie, jeśli uważasz, że coś jest nie tak.
luschn
1
na stosie jest
napisane,
w 2013 roku wszyscy używali jquery - ale obecnie zgadzam się z tym :) - zachowam odpowiedź na przyszłość.
luschn
15

Aby wywołać zdarzenie, po prostu wywołujesz procedurę obsługi zdarzenia dla tego elementu. Niewielka zmiana w stosunku do twojego kodu.

var a = document.getElementById("element");
var evnt = a["onclick"];

if (typeof(evnt) == "function") {
    evnt.call(a);
}
po prostu ostry
źródło
1
+1. Również trochę googlowania ujawnia, że ​​foo.click () to tylko IE, oczywiście mogę się mylić ...
karim79
1
Powinieneś używać notacji z kropką (.onclick) zamiast z notacją w nawiasach (["onclick"]).
Rudd Zwolinski
.onclick () i .click () nie działają zgodnie z oczekiwaniami. W przeglądarce Firefox .click (lub w nawiasach ['kliknięcie']) nie jest to „FUNKCJA”. Ale podczas wywoływania .onclick () tracisz odwołanie „this” (potrzebuję tego w ASP.NET MVC, ponieważ informacje z tagu <a> są potrzebne w funkcji wykonawczej)
Ropstah
5
$("#linkid").trigger("click");
Gość
źródło
2
Witamy w SO. Czy mógłbyś wyjaśnić, dlaczego to działa (co dokładnie robi itp.) I co odróżnia to od innych rozwiązań?
rano
2
po co zaznaczać tę odpowiedź? jest to najlepsze rozwiązanie na tej stronie, jeśli używasz jQuery ... one liner - nie da się tego przebić!
PodTech.io
1
Odpowiedź nie powinna wymagać jQuery
Greg Perham
5

Oczywiście OP stwierdził podobnie, że to nie zadziałało, ale zadziałało dla mnie. Opierając się na notatkach w moim źródle, wydaje się, że został on zaimplementowany mniej więcej w czasie lub po poście OP. Być może teraz jest to bardziej standardowe.

document.getElementsByName('MyElementsName')[0].click();

W moim przypadku mój przycisk nie miał identyfikatora. Jeśli Twój element ma identyfikator, najlepiej użyj następującego (nieprzetestowane).

document.getElementById('MyElementsId').click();

Początkowo próbowałem tej metody i nie zadziałała. Po wygooglowaniu wróciłem i zdałem sobie sprawę, że mój element jest nazwany i nie mam identyfikatora. Dokładnie sprawdź, czy wywołujesz właściwy atrybut.

Źródło: https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click

Tyler Montney
źródło
1

Przyjrzyj się metodzie handleEvent
https://developer.mozilla.org/en-US/docs/Web/API/EventListener

„Surowy” JavaScript:

function MyObj() {
   this.abc = "ABC";
}
MyObj.prototype.handleEvent = function(e) {
   console.log("caught event: "+e.type);
   console.log(this.abc);
}

var myObj = new MyObj();

document.querySelector("#myElement").addEventListener('click', myObj);

Teraz kliknij na swój element (o identyfikatorze „myElement”) i powinien wyświetlić się w konsoli:

złapane zdarzenie: kliknij
ABC

Dzięki temu możesz mieć metodę obiektu jako procedurę obsługi zdarzeń i mieć dostęp do wszystkich właściwości obiektu w tej metodzie.

Nie możesz po prostu przekazać metody obiektu bezpośrednio do addEventListener (tak:) element.addEventListener('click',myObj.myMethod);i oczekiwać, myMethodże będę zachowywał się tak, jakbym był normalnie wywoływany na obiekcie. Zgaduję, że każda funkcja przekazana do addEventListener jest w jakiś sposób kopiowana, a nie odwoływana. Na przykład, jeśli przekażesz odwołanie do funkcji nasłuchiwania zdarzeń do addEventListener (w postaci zmiennej), a następnie cofniesz ustawienie tego odwołania, detektor zdarzeń będzie nadal wykonywany po przechwyceniu zdarzeń.

Innym (mniej eleganckim) obejściem polegającym na przekazaniu metody jako nasłuchiwania zdarzeń thisi zachowaniu dostępu do właściwości obiektu w detektorze zdarzeń byłoby coś takiego:

// see above for definition of MyObj

var myObj = new MyObj();

document.querySelector("#myElement").addEventListener('click', myObj.handleEvent.bind(myObj));
Rolf
źródło
1

Stary wątek, ale pytanie jest nadal aktualne, więc ...

(1) Przykład z twojego pytania DZIAŁA teraz w przeglądarce Firefox. Jednak oprócz wywołania procedury obsługi zdarzeń (która wyświetla alert), klika RÓWNIEŻ łącze, powodując nawigację (po odrzuceniu alertu).

(2) Aby TYLKO wywołać procedurę obsługi zdarzeń (bez wyzwalania nawigacji) wystarczy zamienić:

document.getElementById('linkid').click();

z

document.getElementById('linkid').onclick();
Doin
źródło
0

Jeśli używasz tego wyłącznie do odniesienia się do funkcji w atrybucie onclick, wydaje się to bardzo złym pomysłem. Wydarzenia inline to ogólnie zły pomysł.

Proponuję co następuje:

function addEvent(elm, evType, fn, useCapture) {
    if (elm.addEventListener) {
        elm.addEventListener(evType, fn, useCapture);
        return true;
    }
    else if (elm.attachEvent) {
        var r = elm.attachEvent('on' + evType, fn);
        return r;
    }
    else {
        elm['on' + evType] = fn;
    }
}

handler = function(){
   showHref(el);
}

showHref = function(el) {
   alert(el.href);
}

var el = document.getElementById('linkid');

addEvent(el, 'click', handler);

Jeśli chcesz wywołać tę samą funkcję z innego kodu javascript, symulowanie kliknięcia w celu wywołania funkcji nie jest najlepszym sposobem. Rozważać:

function doOnClick() {
   showHref(document.getElementById('linkid'));
}
David Snabel-Caunt
źródło
chodzi o zachowanie odniesienia do „tego”. Nie mogę wyłącznie wygenerować części onclick w kotwicy (.NET MVC). Muszę wygenerować kompletny tag kotwicy. Ten tag jest całkowicie wymagany przez funkcję onclick (np. Używa atrybutu href).
Ropstah
-1

Generalnie odradzałbym wywoływanie programów obsługi zdarzeń „ręcznie”.

  • Nie jest jasne, co jest wykonywane z powodu wielu zarejestrowanych słuchaczy
  • Niebezpieczeństwo wpadnięcia w cykliczną i nieskończoną pętlę zdarzeń (kliknięcie A wyzwalające kliknięcie B, wyzwalanie kliknięcia A itp.)
  • Nadmiarowe aktualizacje DOM
  • Trudno odróżnić rzeczywiste zmiany w widoku spowodowane przez użytkownika od zmian wprowadzonych jako kod inicjalizacyjny (który należy uruchomić tylko raz).

Lepiej jest dowiedzieć się, co dokładnie chcesz, aby się wydarzyło, umieścić to w funkcji i wywołać to ręcznie ORAZ zarejestrować to jako detektor zdarzeń.

hvdd
źródło
OP zapytał, jak coś zrobić, a nie jak najlepiej coś zrobić. To nie jest CodeReview. Gdybyś odpowiedział na jego pytanie, a następnie złożył zastrzeżenie, byłoby inaczej.
Tyler Montney,