Jak zrobić callback w javascript – minitutorial.

Jedną z największych magicznych mocy wszystkich frameworków i pluginów javascript jest możliwość rozszerzenia ich działania poprzez tak zwane callbacks. Pokażę Wam jak wykonać własny obiekt javascript, który będzie potrafił je obsłużyć.

Po pierwsze potrzebujesz zdefiniować swoją klasę:

function myClass(params){
}

Prościzna ;) Spróbujmy teraz obsłużyć callback beforeInit, który odpali się “najsampierw” przy tworzeniu obiektu:

function myClass(params){
    if(params.beforeInit){
        console.log("beforeInit");
        params.beforeInit();
    }
    console.log("Init complete")
}
console.log("=============");
var a = new myClass(
  {
    beforeInit: function(){console.log("My message!");}
  }
);

Włącz firebuga i sprawdź działanie ;)

=============
beforeInit
My message!
Init complete

Oczywiście Twoja klasa może zechcieć coś zrobić oprócz stworzenia siebie samej ;) Callbacki mogą zachowywać się różnie w zależności od stanu obiektu. Do klasy dodałem metodę doSth i callback beforeRun (który wykonuje się przed wykonaniem metody doSth)

Wypróbuj następujący kod:

function myClass(params){
    if(params.beforeInit){
        console.log("#beforeInit");
        params.beforeInit();
    }

    this.doSth = function() {
        if(params.beforeRun){
            params.beforeRun(this.state);
        }
        console.log("#doSth");
    }

    if(params.state) {
        this.state = params.state;
    }else{
        this.state = false;
    }

    console.log("Init complete")
}
console.log("=============");
var a = new myClass(
  {
    state: 1,
    beforeRun: function(state){
        if(state != false) {
            console.log("Extended! state = " + state);
        }else {
            //do nothing
        }
    }
  }
);
a.doSth();
console.log("=============");
var b = new myClass(
  {
    beforeRun: function(state){
        if(state != false) {
            console.log("Extended! state = " + state);
        }else {
            //do nothing
        }
    }
  }
);
b.doSth();

wynik:

=============
Init complete
Extended! state = 1
#doSth
=============
Init complete
#doSth

Możesz też uzależnić wykonanie metody doSth w zależności od warunków wewnętrznych (parametr state) lub zewnętrznych:

function myClass(params){
    if(params.beforeInit){
        console.log("#beforeInit");
        params.beforeInit();
    }

    this.doSth = function() {
        if(params.beforeRun){
            if(!params.beforeRun(this.state)){
                return;
            }
        }
        console.log("#doSth");
    }

    if(params.state) {
        this.state = params.state;
    }else{
        this.state = false;
    }

    console.log("Init complete")
}
console.log("=============");
var a = new myClass(
  {
    state: 1,
    beforeRun: function(state){
        if(state != false) {
            console.log("Extended! state = " + state);
        }else {
            return false
        }
    }
  }
);
a.doSth();
console.log("=============");
var b = new myClass(
  {
    beforeRun: function(state){
        if(state != false) {
            console.log("Extended! state = " + state);
        }else {
            return false
        }
    }
  }
);
b.doSth();
console.log("=============");
var c = new myClass(
  {
    beforeRun: function(state){
        if( (new Date().getTime())%2  ) {
            console.log("Extended! state = " + state);
        }else {
            return false
        }
    }
  }
);
c.doSth();

Wynik (zależy od aktualnego czasu, więc może okazać się konieczne uruchomienie go kilka razy, zanim otrzymasz identyczny):

=============
Init complete
Extended! state = 1
=============
Init complete
=============
Init complete
Extended! state = false

W przypadku obiektu c metoda run odpali się tylko, jeśli aktualny timestamp jest podzielny przez 2 ;)

To tyle. Mam nadzieję, że pozwoli Wam to wymyślać ciekawsze i bardziej użyteczne fragmenty kodu javascript, nawet tego używanego prywatnie.

Sprytnie zaprojektowana klasa ze sprytnymi callbackami jest bardzo przyjemna – możliwe jest modyfikowanie jej zachowania bez modyfikacji klasy bazowej. To samo podejście znacie pewnie z Behaviors cake’a.

Code snippet: ekstrakcja nazwy pola z inputów cakePHP przy pomocy jQuery

Natknąłem się na następujący problem:

Mam formularz wyszukiwania, który wygląda różnie w różnych widokach, jednak na jego podstawie jest budowany url tak samo dla każdego widoku. Na przykład:

// some view
echo $form->create("Model");
echo $form->input("field1");
echo $form->input("field2");
echo $form->input("field3");
echo $form->end("submit");

W zdarzeniu onsubmit chcę wygenerować taki url:
“/field1:value1/field2:value2/field3:value3″
Gdzie valueX to oczywiście wartość danego pola.

Pobranie interesujących nas pól:

$("form input[type!=submit][name!=_method], form select");

Tak można wytargać nazwę pola z “name” inputów (zakładając, że w zmiennej string mamy cały name):

// string.substr(
//   string.indexOf("[", string.indexOf("]"))
// ).slice(1, -1);
// nowa, lepsza, prostsza wersja:
string.substr(
   string.lastIndexOf("[")
).slice(1, -1)


Całość tworzenia linków:

var params = "";

$("form input[type!=submit][name!=_method], form select").each(
   function(index,element) {
      params +=
         element.name.substr(
            element.name.lastIndexOf("[")
         ).slice(1, -1)+
         ":"+
         element.value+
         "/";
   }
);

Przydaje się, jeśli pracujesz z parametrami “named”