Uvod
U okviru Vue.js svaka komponenta ima svoj izolovani domen, direktna komunikacija izmedju dve komponente po default-u nije dozvoljena, tako da se za razmenu podataka koriste odgovarajuće mehanizmi.
Komunikacija izmedju parent i child komponente može da se odvija u oba smera ali koristeći različite mehanizme. U smeru od parenta ka child komponenti podatak se prosledjuje kroz atribut child taga, a u smeru od child komponente ka parent komponenti se prosledjuje uz custom event.
Treba naglasiti da u zavisnosti od tipa prosledjenog podatka zavisi da li je komunikacija jednosmerna ili dvosmerna. U slučaju podataka primitivnog tipa ova komunikacija je jednosmerna, jer child komponenta čak i da napravi promenu nad prosledjenim podatkom to neće uticati na parent komponentu. Medjutim ako se proslede podaci referentog tipa (nizovi ili objekat), onda promena takvog podatka u child komponenti će se primetiti i iz roditeljske komponente jer obe “posmatraju” isto mesto u memoriji.
1 2 3 4 5 |
<parent-komponenta> <div> <child-komponenta></child-komponenta> </div> </parent-komponenta> |
Ukoliko se pak kao podatak prosledi metoda iz parent komponente, i ako ta metoda menja neki podatak iz parent komponente, onda pozivanjem prosledjene metode iz child komponente takodje menjamo taj podatak u parent komponenti.
Slanje podataka tip: parent -> child
a) Prosledjivanje podatka iz parent komponente
U mehanizmu za prosledjivanju podataka od roditeljske komponente ka child komponenti, podatak se prosledjuje kroz atribut HTML elementa (custom tag elemenat predstavlja instancu child komponente).
String
Ukoliko želimo da prosledimo statički string koji se neće menjati:
1 |
<child my-message="hello!"></child> |
Medjutim kada prosledjujemo primitivni podatak koji se dinamički menja, da bi bio reaktivan moramo da koristimo direktivu v-bind:
1 |
<child v-bind:my-message="parentMsg"></child> |
Sa ovakvim pristupom svaki put kada roditeljska komonenta bude ažurirana sva “prop” svojstva će takodje biti ažurirana.
Number
Za razliku od stringa props koji prosledjuje brojeve mora da bude bind-ovan i za statički i dinamički props:
1 2 3 4 5 |
<!-- Staticki props --> <blog-post v-bind:likes="42"></blog-post> <!-- Dinamicki props --> <blog-post v-bind:likes="post.likes"></blog-post> |
Boolean vrednost
Props svojstvo koje prosledjuje boolean-ovu vrednost takodje mora biti bind-ovano i za statičku i za dinamički vrednost.
1 2 3 4 5 |
<!-- Staticki props --> <base-input v-bind:favorited="false"> <!-- Dinamicki props --> <base-input v-bind:favorited="post.currentUserFavorited"> |
NAPOMENA:
U slučaju prosledjivanja “props” atributa bez definisane vrednosti, Vue.js smatra da je u pitanju booleanova vrednost TRUE:
1 2 |
<!-- prop bez vrednosti je isto kao da smo prosledili `true` --> <blog-post favorited></blog-post> |
Objekat/Array
Kao i za sve ostale tipove, osim String-a “props” svojstvo mora biti bind-ovano i za statičku i dinamičku vrednost.
Array
1 2 3 4 5 |
<!-- Staticki props --> <blog-post v-bind:comment-ids="[234, 266, 273]"></blog-post> <!-- Dinamicki props --> <blog-post v-bind:comment-ids="post.commentIds"></blog-post> |
Object
1 2 3 4 5 |
<!-- Staticki props --> <blog-post v-bind:comments="{ id: 1, title: 'My Journey with Vue' }"></blog-post> <!-- Dinamicki props --> <blog-post v-bind:post="post"></blog-post> |
b) Prihvatanje podatka u child komponenti kroz “props” svojstvo
Da bi child komponenta mogla da iskoristi prosledjeni podatak, potrebno je da ga specifično označi tako što će da ga deklariše kroz svojstvo “props”. Unutar child komonente se kroz svojstvo “props” deklariše koji tip podataka očekuje da joj se prosledi, mogu da se koriste sledeće sintakse:
Array sintaksa
1 2 3 |
Vue.component('props-demo-simple', { props: ['size', 'my-message'] }) |
Objekatna sintaksa
Za razliku od “Array sintakse” “objektna sintaksa” omogućava i validaciju tipa podataka koji se očekuje da bude prosledjen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
Vue.component('props-demo-advanced', { props: { // Osnovna provera tipa podataka (kada se definiše `null` onda nema uslova) propA: Number, // Više mogućih tipova podataka propB: [String, Number] // Zahtev da prosledjeno svojstvo mora da ima vrednost propC: { type: String, required: true }, // Podrazumevana vrednost propD: { type: Number, default: 100 }, // Objekat ili Niz mora biti vraćen kroz Factory funkciju propE: { type: Object, default: function () { return { message: 'hello' } } }, // custom validator funkcija propF: { validator: function (value) { return value > 10 } } } }) |
NAPOMENA:
Nazivi HTML atributa su case-insensitive, tj. browser-i ne razlikuju velika od malih slova. Medjutim Vue.js dozvoljava da se imena “props” atributa pišu kao “camelCase” jer ih obradjuje i od njih generiše “kebab-case” ekvivalente (koji mogu da se koriste u okviru HTML).
Primer
U ovome primeru u okviru JavaScript-a se definiše props svojstvo “postTitle” koristeći “camelCase” pravilo
1 2 3 4 |
Vue.component('blog-post', { props: ['postTitle'], template: '<h3>{{ postTitle }}</h3>' }) |
Medjutim u okviru HTML-a se koristi “post-title” “kebab-case” ekvivalent:
1 |
<blog-post post-title="hello!"></blog-post> |
BONUS Savet:
U slučaju da su nam potrebne vrednosti prosledjenih svojstva kao inicijalne vrednosti preporuka je da definišemo lokalnu promenjivu:
1 2 3 4 |
props: ['initialCounter'], data: function () { return { counter: this.initialCounter } } |
Primer
U ovome primeru parent komponenta prosledjuje preko atributa “podatak” vrednost “brojača”, dok child komponenta taj prosledjeni podatak prihvata kroz istoimeno “props” svojstvo. U ovom primeru je obradjeno samo prosledjivanje podataka iz parent komponente, stoga pri menjanju brojača iz child komponente to neće uticati na vrednost u parent komponenti. Ustvari menjanje vrednosti brojača unutar child komponente je privremeno, jer nakon novog ažuriranja brojača iz parent komponenete, podatak u child-u će se sinhronizovati sa parent komponentom i tako “pregaziti” sve svoje promene napravljene iz child komponente.
Da bi se neki podatak uvek sinhronizovao izmedju parent i child komponente potrebno je da se promene iz child komponente prosledjuju parent komponenti, što je i objašnjeno u sledećoj sekciji.
Slanje podataka tip: child -> parent
Prosledjivanje podataka od child komponente ka roditeljskoj komponenti se vrši tako što emitujemo custom dogadjaj uz koji prosledjujemo i željene podatke. Stoga je potrebno da u okviru roditeljske komponente da osluškujemo taj specifični dogadjaj i kada ga komponenta primeti treba da pokupi prosledjeni podataka.
a) Emitovanje dogadjaja iz child komponente
Dogadjaj se emituje iz child komponente sa naredbom:
1 |
this.$emit('nazivCustomDogadjaja', [nekiPodatak]) |
Treba napomenuti da je child komponenta i dalje potpuno odvojena od onoga što se dešava izvan nje, ona samo izveštava o sopstvenoj aktivnosti (u slučaju da roditeljsku komponentu to interesuje).
b) Osluškivanje custom dogadjaja u parent komponenti
Osluškivanje ovako emitovanog dogadjaja je potpuno isto kao i osluškivanje bilo kog drugog dogadjaja. Za osluškivanje se koristi standardna direktiva “v-on:” v-on:nazivCustomDogadjaja="nekiEventHandler", koja se kači na child tag u okviru parent komponente. Prosledjenom podatku se pristupa preko specifične promenjive $event:
Primer: parent komponenta
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<child-komponenta v-on:nazivCustomDogadjaja="nekiEventHandler"></child-komponenta> <script> new Vue () { data: methods:{ nekiEventHandler: function () { console.log($event); // Vraća vrednost promenjive "nekiPodatak" } } } </script> |
Primer
U ovome primeru je pored prosledjivanja podatka iz parent komponente, nakon izmene u child komponenti je emitovan dogadjaj da obavesti parent komponentu i poslat joj je novi podatak. Parent komponenta zatim ažurira taj podatak i ispisuje promenu.