jComponent - Ako na vlastný komponent #3
Séria Ako na vlastný komponent bude venovaná jComponentu. Ak neviete, čo je to jComponent, tak vám odporúčam článok od Petra Širku. V tejto časti si urobíme accordion. Zúročíme už naše vedomosti a na vrch pridamé novinku v podobe datasource. Môžme sa do toho pustiť.
Bojový plán - Premyslíme si komponent
Ha! Prvá zmena oproti minulému článku. Práve v tento okamih sa odohráva tá najväčšia vojna. Musíme si premyslieť ako vôbec bude fungovať ten komponent. Rád by som vedel, ktoré konkrétne accordion taby sú otvorené. Stačí array s indexami. A samozrejme by bolo super keby som nemusel vypisovať komponent stále v HTML ale mohol som tam šupnuť array a ten by sa o to postaral.
Základný komponent
Tento náš komponent už bude obsahovať aj CSS, takže si pridáme do štýlov tento kód
.accordion-title { cursor: pointer; display: block; padding: 8px 15px; user-select: none; color: gray; }
.accordion-title .pull-right { margin: 2px 0 0; }
.accordion-title b { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; margin-right: 15px; }
.accordion { padding: 0; border-radius: 2px; border: 1px solid #E0E0E0; }
.accordion + .accordion { border-top: 0; }
.accordion .accordion-body { padding: 7px 15px 1px; border-radius: 0 0 2px 2px; background-color: #F8F8F8; }
A začneme s tvorobu. Toto by ste mohli zvládnuť aj sami
COMPONENT('accordion', function(self, config) {
self.nocompile();
self.make = function() {
self.event('click', '.accordion-title', function() {
// pripravíme si rovno event
});
};
});
Ako ste si mohli všimnúť, pribudla novinka self.nocompile()
. Zabezpečí to, že jComponent pri vyhľadávaní (npr. data-bindov) preskočí vnútro komponentu. Lebo my s určitosťou vieme, že tam žiadny data-bind nebude.
Druhý zdroj - datasource
Dynamické data môžme vložiť cez PATH ale niekedy sa nám stane, že to nestačí. Alebo PATH používame na niečo iné. Vtedy je tu ešte jedna možnosť - datasource. Keď použijeme datasource, tak komponent začne sledovať danú cestu (rovnako ako PATH) a zmeny na nej. Datasource je vlastne WATCHer. Nevýhoda je, že komponent môže mať iba jeden datasource (okrem PATH). No nikdy nás to nelimitovalo. Nenarazili sme na prípad, kedy by bolo treba viacero datasource-ov. Pri použití datasource Využijeme aj metódu self.configure
(je to jednoduchá metóda). Ale všetko krásne pochopíte na kóde:
COMPONENT('accordion', function(self, config) {
self.nocompile();
self.configure = function(name, value) { // zvolá sa metóda s parametrami `name` a `value`
switch(name) {
case 'datasource': // ak sa `name` zhoduje nášmu názvu
self.datasource(value, self.bind); // spustíme datasource "watcher" na `value` a pošleme informácie do `self.bind`
break;
}
};
self.bind = function(path, value) {
console.log('path:', path, 'value:', value);
};
self.make = function() {
self.event('click', '.accordion-title', function() {
// pripravíme si rovno event
});
};
});
No a teraz nám stačí už iba deklarovať komponent.
<div data---="accordion__opened__datasource:faq"></div>
Vyskúšame, či nám to funguje. Do konzoly napíšeme SET('faq', 'Hello World');
Kde sa tu vzal (T)Angular?
Tangular je template engine. To je všetko. Fakt. Takto jednoduché to je. Ale aj tak vás odkážem na wiki lebo aj Tangular v sebe skrýva veľké veci. My si vystačíme s Tangular.compile
. Táto funkcia nám zo stringu spraví funkciu do ktorej my potom pošleme iba objekt. Hodí sa pozrieť si aj sekundárny "model" ktorý využijeme aj my a volá sa repository. Čiže si do komponentu pridáme Tangular.compile
.
COMPONENT('accordion', function(self, config) {
var template = Tangular.compile('<div class="accordion" data-index="{{ index }}"><span class="accordion-title"><i class="fa pull-right {{ if $.show }}fa-angle-up{{ else }}fa-angle-down{{ fi }}"></i><b>{{ title }}</b></span><div class="accordion-body{{ if !$.show }} hidden{{ fi }}">{{ body }}</div></div>');
self.nocompile();
self.configure = function(name, value) {
switch(name) {
case 'datasource':
self.datasource(value, self.bind);
break;
}
};
self.bind = function(path, value) {
};
self.make = function() {
self.event('click', '.accordion-title', function() {
});
};
});
Áno, je to neprehľadné. Áno, dal by sa použiť aj iní zápis. Ale ja (neviem ako Peter) mám na to malý trik, napíšem si najskôr celé HTML aj s premennými, podmienkami... A potom to iba zminifikujem do jedného riadka. Podstatné ale je, že teraz môžme konečne vyrenderovať naš accordion.
Renderovanie accordionu
Tu sa teraz odohráva celá mágia. Mágia kúzla zbavená.
COMPONENT('accordion', function(self, config) {
var template = Tangular.compile('<div class="accordion" data-index="{{ index }}"><span class="accordion-title"><i class="fa pull-right {{ if $.show }}fa-angle-up{{ else }}fa-angle-down{{ fi }}"></i><b>{{ title }}</b></span><div class="accordion-body{{ if !$.show }} hidden{{ fi }}">{{ body }}</div></div>');
self.nocompile();
self.configure = function(name, value) {
switch(name) {
case 'datasource':
self.datasource(value, self.bind);
break;
}
};
self.bind = function(path, value) {
if (!value || !value.length)
return; // Ak je datasource prázdny alebo neexistuje
var data = self.get(); // získame data z __PATH__ - aby niektoré mohli byť otvorené cez SET
var builder = [];
for (var i = 0; i < value.length; i++) {
var item = value[i];
item.index = i; // uložíme si do itemu aj index, ten vyrenderujeme ako daza-index a využijeme ho pri `click` evente
var settings = { show: (data.indexOf(i) !== -1) }; // do repository modelu pošleme či má byť zobrazený alebo nie
builder.push(template(item, settings)); // do nášho pola push-neme template
}
self.html(builder.join('')); // konvertujeme array na string a vyrenderujeme
};
self.make = function() {
self.event('click', '.accordion-title', function() {
});
};
});
Finálna fáza
V tento moment by v ideálnom svete bolo počuť hlášku FINISH HIM a ja by som urobil nejaké ultra kombo v štýle, že by som na ten komponent skočil a rozpučil ho. Holt, budeme si musieť vystačiť aj bez toho. Posledná vec ktorá nám chýba do celej skládačky je zobrazenie/skrytie po kliknutí. A ako sa presvedčíme, to nie je nič zložité.
COMPONENT('accordion', function(self, config) {
var template = Tangular.compile('<div class="accordion" data-index="{{ index }}"><span class="accordion-title"><i class="fa pull-right {{ if $.show }}fa-angle-up{{ else }}fa-angle-down{{ fi }}"></i><b>{{ title }}</b></span><div class="accordion-body{{ if !$.show }} hidden{{ fi }}">{{ body }}</div></div>');
self.nocompile();
self.configure = function(name, value) {
switch(name) {
case 'datasource':
self.datasource(value, self.bind);
break;
}
};
self.bind = function(path, value) {
if (!value || !value.length)
return;
var data = self.get();
var builder = [];
for (var i = 0; i < value.length; i++) {
var item = value[i];
item.index = i;
var settings = { show: (data.indexOf(i) !== -1) };
builder.push(template(item, settings));
}
self.html(builder.join(''));
};
self.make = function() {
self.event('click', '.accordion-title', function() {
var icon = $(this).find('.fa'); // uložíme si ikonu pre ďalšie použitie
var parent = $(this).parent(); // uložíme si parenta
var body = parent.find('.accordion-body'); // nájdeme `accordion-body`
var ishidden = body.hclass('hidden'); // skontrolujeme, či `accordion-body` je skrytý
var index = +parent.attrd('index'); // získame náš index ktorý sme si podstivo vytvorili a prevedieme ho na integer (to malé, bezvýznamné + o ktorom všetci učitelia hovorili)
var data = self.get(); // získame aktuálne data v __PATH__
icon.rclass2('fa-angle');
icon.aclass((ishidden ? 'fa-angle-up' : 'fa-angle-down'));
if (ishidden) {
data.push(index);
body.rclass('hidden');
}
else {
data = data.remove(index);
body.aclass('hidden');
}
self.set(data, 2); // nastavíme __PATH__ aktuálne data, 2 je typ `input`. Dali sme hodnotu `2` preto, aby sme mohli jednoduchšie odchytiť/detekovať kto vyvolal zmenu (či manual alebo component alebo init)
});
};
});
Game Over
Toto je už vážne všetko. Máme vlastný komponent. Osobne si myslím, že tento náš komponent je už použiteľný. Pôvodne som chcel vysvetliť niečo iné ale to si necháme zase nabudúce. V ďalšej časti spravíme radio button ktorý bude vyzerať takto a takto. To aby ste mali predstavu, čo sa naučíme nabudúce. Mimo to pripravujem ďalšiu sériu v ktorej urobíme celú appku postavenú na Total.js a jComponente.
Download
V minulých častiach mi to prišlo ako hlúposť ale tentokrát sem dám celý script na stiahnutie accordion.html (5 KB)