Dynamically creating element on polymer#2.0 นะจร๊ะ

ปกติเวลาเราจะแทรก Element สักหนึ่งตัวเนี้ย เราก็แค่ป้อน Tag ที่เราต้องการ กำหนด Attribute, Properties, Content เข้าไปใน Template แบบนี้

<template>
<div id="container">
<my-cat name="Miki" emotion="{{emo}}"> meow </my-cat>
</div>
</template>

แต่มีบาง“งาน”ครับ ที่ไม่สามารถที่ใช้วิธีด้านบนได้ เนื่องจากว่างานนั้นมีความถี่ในการสับเปลี่ยน Element ในจุดๆนั้นบ่อยมาก และไม่มี Element ที่ใช้ซ้ำกันเลย (Dynamic element) ดังนั้นเราต้องใช้วิธีการแทรก Element แบบ Dynamic ตามตัวอย่างด้านล่างครับ

<template>
<div id="container"></div>
</template>
static get properties() {
return {
emo: {
type: String,
value: 'Happy'
}
}
}
ready(){
super.ready()
   this.myCat = document.createElement('my-cat')
this.myCat.innerHTML = ' meow '
this.myCat.setAttribute('name','Miki')
this.myCat.emotion = this.emo
this.$.container.appendChild(this.myCat)
}

ผลลัพธ์ก็จะออกแบบเดียวกันกับแบบแรกครับ เป็นไงละ… เอาไปใช้ได้หลายงานเลยนะคร๊าบบบ แต่เดี๋ยวก่อน!!! หากคุณเอาไปใช้.. ปัญหาที่ตามมาก็คือเรื่อง Data binding ครับ

เนื่องจากว่ามันไม่ได้แทรก Element แบบปกติมันก็เลยไม่สามารถทำ Data binding ได้ครับ จากตัวอย่างด้านบนเราก็แค่ เอาค่า this.emo จาก Element แม่ มาป้อนใส่ตรงๆให้กับ Element my-cat เท่านั้น ถ้าหากค่าของ Element แม่เปลี่ยน ​Element ลูกจะไม่เปลี่ยนตาม หากลูกเปลี่ยนแม่ก็ไม่เปลี่ยนเช่นกัน (2 way case)

ซึ่งมันก็มีวิธีแก้ไขปัญหาครับ แต่ก็ไม่ Perfect เท่าไหร่หรอกครับ แต่เรียกได้ว่าแก้ขัดได้ในระดับหนึ่ง มันเป็นการใช้ Observer และ Event เข้ามาช่วยในการ Binding ครับ

//หากต้องการให้ข้อมูลไหลจาก Element แม่ไปลูก เราจะใช้ Observer ครับ
static get properties() {
return {
emo: {
type: String,
value: 'Happy',
observer: '_setVal'
}
}
}
_setVal(val){
   if(this.myCat){
if(this.myCat.emotion!=val)
this.myCat.emotion = val
}
}

ข้อมูลไหลลงแล้ว ถึงตาไหลขึ้นบ้าง

//หากต้องการข้อมูลจาก Element ลูกย้อนกลับไปหาแม่ เราจะใช้ Event ครับ
ready(){
super.ready()
   this.myCat = document.createElement('my-cat')
this.myCat.innerHTML = ' meow '
this.myCat.setAttribute('name','Miki')
this.myCat.emotion = this.emo
   this.myCat.addEventListener('emotion-changed', this.getVal())
   this.$.container.appendChild(this.myCat)
}
getVal(_this){
var _this = this
return function (evt) {
if(_this.emo != evt.detail.value)
_this.emo = evt.detail.value
};
}

เพียงเท่านี้เราก็ได้ Data binding ฉบับแก้ขัดแล้วครับ


ถ้าหากคุณไม่ได้ต้องการให้ แม่กับลูก binding กัน แต่อยากให้ลูกกับลูกคุยกันแทนละ!! เราจะใช้ helper element ของ polymer ที่ชื่อว่า dom-bind

ซึ่ง dom-bind มันก็เป็น Element เอาไว้สำหรับให้ข้อมูล Binding กันได้ แม้จะไม่อยู่ใน polymer ก็ตาม พูดง่ายๆคือไม่ต้องมี Element แม่ ลูกก็คุยกันเองได้ ว้าวววว.. ไหมละ!!

แต่ในที่นี้เราจะมาใช้ช่วย Binding ข้อมูลระหว่างลูกกับลูก โดยมีแม่ครอบอยู่อีกที แต่ว่าข้อมูลจากแม่จะไม่สามารถไหลไปหาลูกนะครับ เพราะมันติด dom-bind นี่แหละ //จริงๆถ้าจะทำก็ทำได้ครับ

ว่าแล้วเราก็มาทำกันเลยดีกว่า . ทีนี้เรามาลองจินตนาการว่าเราจะสร้าง Element หน้าตาแบบนี้

<template>
<div id="container">
      <dom-bind>
<template>
<my-cat name="Miki" talk="{{say}}"> meow </my-cat>
<my-dog name="Dig" talk="{{say}}"> hong </my-dog>
</template>
</dom-bind>
   </div>
</template>

แต่เราจะเขียนแบบด้านล่างนี้นะ

ready(){
super.ready()
   var domBind = document.createElement('dom-bind')
var template = document.createElement('template')
domBind.appendChild(template)
   var doc = template.content.ownerDocument
   this.myCat = doc.createElement('my-cat')
this.myCat.innerHTML = ' meow '
this.myCat.setAttribute('name','Miki')
this.myCat.setAttribute('talk','{{say}}')
   this.myDog = doc.createElement('my-dog')
this.myDog.innerHTML = ' hong '
this.myDog.setAttribute('name','Dig')
this.myDog.setAttribute('talk','{{say}}')
   template.content.appendChild(this.myCat)
template.content.appendChild(this.myDog)
   this.$.container.appendChild(domBind)
}

เพียงเท่านี้พี่น้องก็คุยกันอย่าง Perfect แล้วครับ ไม่ต้องมีการดัก Observer ไม่ต้องมีการดัก Event

วิธีการ binding ข้อมูลแบบนี้มันจะคล้ายกับการทำงานภายใต้ผ้าคลุมของ Polymer เอ้า… งงละซิ Under the hood ไง ผ่าาม..

จริงๆแล้วแล้วเรื่อง Data Binding ของ ​Polymer ค่อนข้างที่จะปวดตับเลยทีเดียวครับ เนื่องจากมีเรื่อง Performance มาเกี่ยวข้อง Polymer จึงตั้งค่าเริ่มต้นที่ Dirty checking ครับ ใครที่เคยทำมาบ้างจะรู้ถึงจุดนี้ ซึ่งผมจะอธิบายอย่างละเอียดภายหลังครับ

ยังไงถ้า ผมผิดพลาดตรงไหนก็ ทักท้วงกันได้ครับ จะแก้ไขให้ อ่านไม่รู้เรื่องก็บอกหน่อยนะครับ ว่าจะให้ขยายความตรงไหนก็บอกกันครับ “ชั้น..รู้ดีว่าลวกๆเกินไป เย้ยยย…” //คือจริงๆก็พูดไม่รู้เรื่องอยู่แล้ว

สำหรับ บทความนี้ผมขอลาไปก่อน ง่วงนอนแล้ว ฝันดีครับ