8 ข้อผิดพลาดที่พบบ่อยที่สุดที่นักพัฒนา Ember.js ทำ
เผยแพร่แล้ว: 2022-03-11Ember.js เป็นเฟรมเวิร์กที่ครอบคลุมสำหรับการสร้างแอปพลิเคชันฝั่งไคลเอ็นต์ที่ซับซ้อน หลักการประการหนึ่งคือ "การโต้แย้งเกี่ยวกับการกำหนดค่า" และความเชื่อมั่นว่ามีการพัฒนาส่วนใหญ่ร่วมกันในแอปพลิเคชันเว็บส่วนใหญ่ และเป็นวิธีที่ดีที่สุดวิธีเดียวในการแก้ปัญหาส่วนใหญ่ในชีวิตประจำวันเหล่านี้ อย่างไรก็ตาม การค้นหานามธรรมที่ถูกต้องและครอบคลุมทุกกรณี ต้องใช้เวลาและข้อมูลจากทั้งชุมชน ในการให้เหตุผล จะดีกว่าที่จะใช้เวลาในการหาวิธีแก้ปัญหาสำหรับปัญหาหลักที่ถูกต้อง จากนั้นจึงรวมเข้ากับกรอบงาน แทนที่จะยกมือขึ้นและปล่อยให้ทุกคนป้องกันตัวเองเมื่อพวกเขาต้องการหาทางแก้ไข
Ember.js มีการพัฒนาอย่างต่อเนื่องเพื่อให้การพัฒนาง่ายยิ่งขึ้น แต่เช่นเดียวกับเฟรมเวิร์กขั้นสูงอื่นๆ ยังคงมีข้อผิดพลาดที่นักพัฒนาของ Ember อาจตกอยู่ใน ด้วยโพสต์ต่อไปนี้ ฉันหวังว่าจะให้แผนที่เพื่อหลีกเลี่ยงสิ่งเหล่านี้ กระโดดเข้าไปเลย!
ข้อผิดพลาดทั่วไปหมายเลข 1: คาดว่า Model Hook จะเริ่มทำงานเมื่อวัตถุบริบททั้งหมดถูกส่งผ่านไป
สมมติว่าเรามีเส้นทางต่อไปนี้ในแอปพลิเคชันของเรา:
Router.map(function() { this.route('band', { path: 'bands/:id' }, function() { this.route('songs'); }); });
เส้นทาง band
มีส่วนไดนามิก id
เมื่อโหลดแอปด้วย URL เช่น /bands/24
24
จะถูกส่งต่อไปยัง hook model
ของเส้นทางที่เกี่ยวข้อง band
model hook มีบทบาทในการดีซีเรียลไลซ์เซ็กเมนต์เพื่อสร้างอ็อบเจ็กต์ (หรืออาร์เรย์ของอ็อบเจ็กต์) ที่สามารถนำมาใช้ในเทมเพลตได้:
// app/routes/band.js export default Ember.Route.extend({ model: function(params) { return this.store.find('band', params.id); // params.id is '24' } });
จนถึงตอนนี้ดีมาก อย่างไรก็ตาม มีวิธีอื่นในการเข้าสู่เส้นทางมากกว่าการโหลดแอปพลิเคชันจากแถบนำทางของเบราว์เซอร์ หนึ่งในนั้นกำลังใช้ตัวช่วย link-to
จากเทมเพลต ตัวอย่างต่อไปนี้จะผ่านรายการวงดนตรีและสร้างลิงก์ไปยังเส้นทาง band
ที่เกี่ยวข้อง:
{{#each bands as |band|}} {{link-to band.name "band" band}} {{/each}}
อาร์กิวเมนต์สุดท้ายสำหรับ link-to, band
เป็นอ็อบเจ็กต์ที่เติมในส่วนไดนามิกสำหรับเส้นทาง และทำให้ id
กลายเป็นเซ็กเมนต์ id สำหรับเส้นทาง กับดักที่หลายคนตกหล่นคือ model hook นั้นไม่ได้ถูกเรียกในกรณีนี้ เนื่องจาก model นั้นรู้อยู่แล้วและได้ถูกส่งผ่านไปแล้ว มันสมเหตุสมผลและอาจบันทึกคำขอไปยังเซิร์ฟเวอร์ แต่เป็นที่ยอมรับ ไม่ใช่ ใช้งานง่าย วิธีที่แยบยลคือการผ่านเข้าไป ไม่ใช่ตัววัตถุ แต่เป็น id:
{{#each bands as |band|}} {{link-to band.name "band" band.id}} {{/each}}
แผนการบรรเทาทุกข์ของ Ember
องค์ประกอบที่กำหนดเส้นทางได้จะมาถึง Ember ในไม่ช้า อาจเป็นเวอร์ชัน 2.1 หรือ 2.2 เมื่อลงจอด โมเดล hook จะถูกเรียกเสมอ ไม่ว่าจะเปลี่ยนไปเป็นเส้นทางที่มีเซ็กเมนต์ไดนามิกอย่างไร อ่าน RFC ที่เกี่ยวข้องที่นี่
ข้อผิดพลาดทั่วไปหมายเลข 2: ลืมไปว่าตัวควบคุมที่ขับเคลื่อนด้วยเส้นทางนั้นเป็นซิงเกิลตัน
เส้นทางใน Ember.js ตั้งค่าคุณสมบัติบนคอนโทรลเลอร์ที่ทำหน้าที่เป็นบริบทสำหรับเทมเพลตที่เกี่ยวข้อง ตัวควบคุมเหล่านี้เป็นแบบซิงเกิลตัน และด้วยเหตุนี้ สถานะใดๆ ที่กำหนดไว้จะยังคงมีอยู่แม้ว่าตัวควบคุมจะไม่ทำงานอีกต่อไป
นี่คือสิ่งที่มองข้ามได้ง่ายมากและฉันก็สะดุดเข้ากับสิ่งนี้เช่นกัน ในกรณีของฉัน ฉันมีแอปแคตตาล็อกเพลงที่มีวงดนตรีและเพลง แฟ songCreationStarted
บนตัวควบคุม songs
ระบุว่าผู้ใช้ได้เริ่มสร้างเพลงสำหรับวงดนตรีใดวงดนตรีหนึ่งแล้ว ปัญหาคือว่าถ้าผู้ใช้เปลี่ยนไปใช้วงดนตรีอื่น คุณค่าของ songCreationStarted
ยังคงอยู่ และดูเหมือนว่าเพลงที่จบไปครึ่งวงจะเป็นของอีกวง ซึ่งทำให้สับสน
วิธีแก้ไขคือรีเซ็ตคุณสมบัติของคอนโทรลเลอร์ด้วยตนเองที่เราไม่ต้องการค้างอยู่ ที่หนึ่งที่เป็นไปได้ในการทำเช่นนี้คือ hook setupController
ของเส้นทางที่เกี่ยวข้อง ซึ่งถูกเรียกในการเปลี่ยนทั้งหมดหลังจาก hook ของ afterModel
(ซึ่งตามชื่อของมันแนะนำ มาหลังจาก hook model
):
// app/routes/band.js export default Ember.Route.extend({ setupController: function(controller, model) { this._super(controller, model); controller.set('songCreationStarted', false); } });
แผนการบรรเทาทุกข์ของ Ember
อีกครั้งที่การเริ่มต้นของส่วนประกอบที่กำหนดเส้นทางได้จะช่วยแก้ปัญหานี้ ส่งผลให้คอนโทรลเลอร์สิ้นสุดลงโดยสิ้นเชิง ข้อดีอย่างหนึ่งของส่วนประกอบที่กำหนดเส้นทางได้คือมีวงจรชีวิตที่สม่ำเสมอมากขึ้น และมักจะขาดเมื่อเปลี่ยนเส้นทางออกจากเส้นทาง เมื่อพวกเขามาถึงปัญหาข้างต้นจะหายไป
ข้อผิดพลาดทั่วไปหมายเลข 3: ไม่เรียกการใช้งานเริ่มต้นใน setupController
เส้นทางใน Ember มีตะขอเกี่ยวกับวงจรชีวิตจำนวนหนึ่งเพื่อกำหนดลักษณะการทำงานเฉพาะแอปพลิเคชัน เราเห็น model
ที่ใช้ดึงข้อมูลสำหรับเทมเพลตที่เกี่ยวข้องและ setupController
สำหรับการตั้งค่าคอนโทรลเลอร์ บริบทของเทมเพลต
หลังนี้ setupController
มีค่าเริ่มต้นที่เหมาะสม ซึ่งกำหนดโมเดลจาก hook model
เป็นคุณสมบัติ model
ของคอนโทรลเลอร์:
// ember-routing/lib/system/route.js setupController(controller, context, transition) { if (controller && (context !== undefined)) { set(controller, 'model', context); } }
( context
คือชื่อที่ใช้โดยแพ็คเกจ ember-routing
สำหรับสิ่งที่ฉันเรียกว่า model
ด้านบน)
ตะขอ setupController
สามารถแทนที่ได้เพื่อวัตถุประสงค์หลายประการ เช่น การรีเซ็ตสถานะของตัวควบคุม (ดังในข้อผิดพลาดทั่วไปหมายเลข 2 ด้านบน) อย่างไรก็ตาม หากลืมเรียกการใช้งานพาเรนต์ที่ฉันคัดลอกไว้ด้านบนใน Ember.Route ผู้ใช้อาจอยู่ในเซสชั่นการเกาหัวเป็นเวลานาน เนื่องจากคอนโทรลเลอร์จะไม่มีชุดคุณสมบัติของ model
ดังนั้นให้เรียกสิ่งนี้เสมอ this._super(controller, model)
:
export default Ember.Route.extend({ setupController: function(controller, model) { this._super(controller, model); // put the custom setup here } });
แผนการบรรเทาทุกข์ของ Ember
ตามที่กล่าวไว้ก่อนหน้านี้ ตัวควบคุมและตะขอ setupController
จะหายไปในไม่ช้า ดังนั้นหลุมพรางนี้จะไม่เป็นอันตรายอีกต่อไป อย่างไรก็ตาม มีบทเรียนให้เรียนรู้มากกว่านี้ คือการคำนึงถึงการนำไปปฏิบัติในบรรพบุรุษ ฟังก์ชัน init
ที่กำหนดไว้ใน Ember.Object
ซึ่งเป็นแม่ของอ็อบเจ็กต์ทั้งหมดใน Ember เป็นอีกตัวอย่างหนึ่งที่คุณต้องระวัง
ข้อผิดพลาดทั่วไปหมายเลข 4: การใช้ this.modelFor
กับเส้นทางที่ไม่ใช่พาเรนต์
เราเตอร์ Ember แก้ไขโมเดลสำหรับแต่ละส่วนของเส้นทางขณะที่ประมวลผล URL สมมติว่าเรามีเส้นทางต่อไปนี้ในแอปพลิเคชันของเรา:
Router.map({ this.route('bands', function() { this.route('band', { path: ':id' }, function() { this.route('songs'); }); }); });
กำหนด URL ของ /bands/24/songs
, model
hook ของ bands
, bands.band
และ bands.band.songs
จะถูกเรียกตามลำดับนี้ เส้นทาง API มีวิธีการที่สะดวกเป็นพิเศษ modelFor
ซึ่งสามารถใช้ในเส้นทางย่อยเพื่อดึงโมเดลจากหนึ่งในเส้นทางหลัก เนื่องจากโมเดลนั้นได้รับการแก้ไขโดยจุดนั้นอย่างแน่นอน
ตัวอย่างเช่น รหัสต่อไปนี้เป็นวิธีที่ถูกต้องในการดึงวัตถุวงดนตรีในเส้นทาง bands.band
:
// app/routes/bands/band.js export default Ember.Route.extend({ model: function(params) { var bands = this.modelFor('bands'); return bands.filterBy('id', params.id); } });
อย่างไรก็ตาม ข้อผิดพลาดทั่วไปคือการใช้ชื่อเส้นทางใน modelFor ที่ ไม่ใช่ พาเรนต์ของเส้นทาง หากเส้นทางจากตัวอย่างข้างต้นมีการเปลี่ยนแปลงเล็กน้อย:
Router.map({ this.route('bands'); this.route('band', { path: 'bands/:id' }, function() { this.route('songs'); }); });
วิธีการดึงแถบความถี่ที่กำหนดใน URL ของเราจะเสียหาย เนื่องจากเส้นทางของ bands
ด์ไม่ใช่พาเรนต์อีกต่อไป ดังนั้นจึงไม่ได้รับการแก้ไขโมเดลของเส้นทาง
// app/routes/bands/band.js export default Ember.Route.extend({ model: function(params) { var bands = this.modelFor('bands'); // `bands` is undefined return bands.filterBy('id', params.id); // => error! } });
วิธีแก้ไขคือใช้ modelFor
สำหรับเส้นทางหลักเท่านั้น และใช้วิธีการอื่นในการดึงข้อมูลที่จำเป็นเมื่อไม่สามารถใช้ modelFor
เช่น การดึงข้อมูลจากร้านค้า
// app/routes/bands/band.js export default Ember.Route.extend({ model: function(params) { return this.store.find('band', params.id); } });
ข้อผิดพลาดทั่วไปหมายเลข 5: การเข้าใจผิดเกี่ยวกับบริบทที่การดำเนินการของคอมโพเนนต์เริ่มทำงาน
ส่วนประกอบที่ซ้อนกันเป็นส่วนที่ยากที่สุดของ Ember ในการให้เหตุผลเสมอมา ด้วยการแนะนำพารามิเตอร์บล็อกใน Ember 1.10 ความซับซ้อนจำนวนมากได้รับการบรรเทาลง แต่ในหลาย ๆ สถานการณ์ ยังคงเป็นเรื่องยากที่จะดูได้อย่างรวดเร็วว่าองค์ประกอบใดที่เรียกใช้จากองค์ประกอบย่อยจะถูกทริกเกอร์
สมมติว่าเรามีองค์ประกอบ band-list
วงดนตรีที่มี band-list-items
อยู่ในนั้น และเราสามารถทำเครื่องหมายแต่ละวงเป็นรายการโปรดในรายการได้
// app/templates/components/band-list.hbs {{#each bands as |band|}} {{band-list-item band=band faveAction="setAsFavorite"}} {{/each}}
ชื่อการดำเนินการที่ควรเรียกใช้เมื่อผู้ใช้คลิกที่ปุ่มนั้นจะถูกส่งผ่านไปยังองค์ประกอบ band-list-item
และกลายเป็นค่าของคุณสมบัติ faveAction

ตอนนี้มาดูคำจำกัดความของเทมเพลตและองค์ประกอบของ band-list-item
:
// app/templates/components/band-list-item.hbs <div class="band-name">{{band.name}}</div> <button class="fav-button" {{action "faveBand"}}>Fave this</button>
// app/components/band-list-item.js export default Ember.Component.extend({ band: null, faveAction: '', actions: { faveBand: { this.sendAction('faveAction', this.get('band')); } } });
เมื่อผู้ใช้คลิกปุ่ม “ชื่นชอบสิ่งนี้” การทำงานของ faveBand
จะถูกทริกเกอร์ ซึ่งจะเริ่มการทำงานของ faveAction
ของส่วนประกอบที่ถูกส่งผ่านไป ( setAsFavorite
ในกรณีข้างต้น) ในองค์ประกอบหลัก band-list
สิ่งนี้ทำให้ผู้คนจำนวนมากสะดุดเนื่องจากพวกเขาคาดหวังว่าการดำเนินการจะถูกไล่ออกในลักษณะเดียวกับการทำงานจากเทมเพลตที่ขับเคลื่อนด้วยเส้นทางบนตัวควบคุม สิ่งที่ทำให้แย่กว่านี้คือไม่มีบันทึกข้อความแสดงข้อผิดพลาด องค์ประกอบหลักเพียงแค่กลืนข้อผิดพลาด
กฎทั่วไปคือการดำเนินการจะดำเนินการในบริบทปัจจุบัน ในกรณีของเทมเพลตที่ไม่มีส่วนประกอบ บริบทนั้นเป็นคอนโทรลเลอร์ปัจจุบัน ในขณะที่ในกรณีของเทมเพลตส่วนประกอบ จะเป็นองค์ประกอบหลัก (ถ้ามี) หรือคอนโทรลเลอร์ปัจจุบันอีกครั้งหากส่วนประกอบไม่ได้ซ้อนกัน
ดังนั้นในกรณีข้างต้น ส่วนประกอบ band-list
จะต้องเริ่มการทำงานใหม่ที่ได้รับจาก band-list-item
เพื่อที่จะทำให้มันเป็นฟองขึ้นไปที่ตัวควบคุมหรือเส้นทาง
// app/components/band-list.js export default Ember.Component.extend({ bands: [], favoriteAction: 'setFavoriteBand', actions: { setAsFavorite: function(band) { this.sendAction('favoriteAction', band); } } });
หากกำหนด band-list
bands
ในเทมเพลตแบนด์ การดำเนินการ setFavoriteBand
จะต้องได้รับการจัดการในตัวควบคุม bands
ด์หรือเส้นทาง bands
ด์ (หรือหนึ่งในเส้นทางหลัก)
แผนการบรรเทาทุกข์ของ Ember
คุณสามารถจินตนาการได้ว่าสิ่งนี้จะซับซ้อนมากขึ้นหากมีการซ้อนระดับมากขึ้น (เช่น โดยการมีองค์ประกอบ fav-button
ภายใน band-list-item
) คุณต้องเจาะรูหลายชั้นจากด้านในเพื่อส่งข้อความของคุณ กำหนดชื่อที่มีความหมายในแต่ละระดับ ( setAsFavorite
, favoriteAction
, faveAction
ฯลฯ )
สิ่งนี้ทำให้ง่ายขึ้นโดย “Improved Actions RFC” ซึ่งมีอยู่แล้วในมาสเตอร์แบรนช์ และอาจรวมอยู่ใน 1.13
ตัวอย่างข้างต้นจะถูกทำให้ง่ายขึ้นเพื่อ:
// app/templates/components/band-list.hbs {{#each bands as |band|}} {{band-list-item band=band setFavBand=(action "setFavoriteBand")}} {{/each}}
// app/templates/components/band-list-item.hbs <div class="band-name">{{band.name}}</div> <button class="fav-button" {{action "setFavBand" band}}>Fave this</button>
ข้อผิดพลาดทั่วไปหมายเลข 6: การใช้คุณสมบัติของอาร์เรย์เป็นคีย์ที่ขึ้นต่อกัน
คุณสมบัติที่คำนวณได้ของ Ember ขึ้นอยู่กับคุณสมบัติอื่นๆ และการพึ่งพานี้จำเป็นต้องกำหนดโดยนักพัฒนาอย่างชัดเจน สมมติว่าเรามีคุณสมบัติ isAdmin
ที่ควรจะเป็นจริงก็ต่อเมื่อบทบาทใดบทบาทหนึ่งคือ admin
นี่คือวิธีที่ใคร ๆ ก็เขียนได้:
isAdmin: function() { return this.get('roles').contains('admin'); }.property('roles')
ด้วยคำจำกัดความข้างต้น ค่าของ isAdmin
จะใช้งานไม่ได้หากตัวอ็อบเจ็กต์อาร์เรย์ roles
เปลี่ยนแปลงไปเอง แต่จะไม่ถูกลบหากมีการเพิ่มหรือลบรายการในอาร์เรย์ที่มีอยู่ มีไวยากรณ์พิเศษเพื่อกำหนดว่าการเพิ่มและการลบควรทริกเกอร์การคำนวณใหม่ด้วย:
isAdmin: function() { return this.get('roles').contains('admin'); }.property('roles.[]')
ข้อผิดพลาดทั่วไปหมายเลข 7: ไม่ใช้วิธีการที่เป็นมิตรกับผู้สังเกตการณ์
มาขยายตัวอย่าง (แก้ไขแล้ว) จากข้อผิดพลาดทั่วไปหมายเลข 6 และสร้างคลาสผู้ใช้ในแอปพลิเคชันของเรา
var User = Ember.Object.extend({ initRoles: function() { var roles = this.get('roles'); if (!roles) { this.set('roles', []); } }.on('init'), isAdmin: function() { return this.get('roles').contains('admin'); }.property('roles.[]') });
เมื่อเราเพิ่มบทบาท admin
ให้กับ User
เรารู้สึกประหลาดใจ:
var user = User.create(); user.get('isAdmin'); // => false user.get('roles').push('admin'); user.get('isAdmin'); // => false ?
ปัญหาคือผู้สังเกตการณ์จะไม่เริ่มทำงาน (และคุณสมบัติที่คำนวณจะไม่ได้รับการอัปเดต) หากใช้วิธี Javascript ของหุ้น สิ่งนี้อาจเปลี่ยนแปลงได้หากการนำ Object.observe
ไปใช้ทั่วโลกในเบราว์เซอร์ดีขึ้น แต่จนถึงตอนนี้ เราต้องใช้ชุดของวิธีการที่ Ember มีให้ ในกรณีปัจจุบัน pushObject
เทียบเท่ากับผู้สังเกตการณ์ที่เป็นมิตรกับ push
:
user.get('roles').pushObject('admin'); user.get('isAdmin'); // => true, finally!
ข้อผิดพลาดทั่วไปหมายเลข 8: การกลายพันธุ์ผ่านคุณสมบัติในส่วนประกอบ
ลองนึกภาพว่าเรามีองค์ประกอบการ star-rating
ซึ่งแสดงการให้คะแนนของรายการและอนุญาตให้ตั้งค่าการให้คะแนนของรายการได้ การจัดอันดับอาจเป็นเพลง หนังสือ หรือทักษะการเลี้ยงลูกของนักฟุตบอล
คุณจะใช้มันแบบนี้ในเทมเพลตของคุณ:
{{#each songs as |song|}} {{star-rating item=song rating=song.rating}} {{/each}}
สมมติว่าส่วนประกอบนั้นแสดงดาว ดาวเต็มหนึ่งดวงสำหรับแต่ละจุด และดาวว่างหลังจากนั้น จนถึงระดับสูงสุด เมื่อมีการคลิกดาว การทำงานของ set
จะเริ่มทำงานบนคอนโทรลเลอร์ และควรตีความว่าเป็นผู้ใช้ที่ต้องการอัปเดตการให้คะแนน เราสามารถเขียนโค้ดต่อไปนี้เพื่อให้บรรลุสิ่งนี้:
// app/components/star-rating.js export default Ember.Component.extend({ item: null, rating: 0, (...) actions: { set: function(newRating) { var item = this.get('item'); item.set('rating', newRating); return item.save(); } } });
นั่นจะทำให้งานเสร็จ แต่มีปัญหาสองสามอย่างกับมัน อันดับแรก ถือว่ารายการที่ส่งผ่านมีคุณสมบัติ rating
ดังนั้นเราจึงไม่สามารถใช้องค์ประกอบนี้เพื่อจัดการทักษะการเลี้ยงลูกของลีโอ เมสซี (ซึ่งคุณสมบัตินี้อาจเรียกว่า score
)
ประการที่สอง มันเปลี่ยนการให้คะแนนของรายการในองค์ประกอบ สิ่งนี้นำไปสู่สถานการณ์ที่ยากจะเข้าใจว่าทำไมคุณสมบัติบางอย่างจึงเปลี่ยนไป ลองนึกภาพว่าเรามีองค์ประกอบอื่นในเทมเพลตเดียวกันที่ใช้การให้คะแนนนั้นด้วย เช่น สำหรับการคำนวณคะแนนเฉลี่ยสำหรับนักฟุตบอล
สโลแกนสำหรับบรรเทาความซับซ้อนของสถานการณ์นี้คือ "Data down, actions up" (DDAU) ควรส่งต่อข้อมูล (จากเส้นทางไปยังตัวควบคุมไปยังส่วนประกอบ) ในขณะที่ส่วนประกอบควรใช้การดำเนินการเพื่อแจ้งบริบทเกี่ยวกับการเปลี่ยนแปลงในข้อมูลเหล่านี้ ดังนั้นควรใช้ DDAU ที่นี่อย่างไร
มาเพิ่มชื่อการดำเนินการที่ควรส่งเพื่ออัปเดตการให้คะแนน:
{{#each songs as |song|}} {{star-rating item=song rating=song.rating setAction="updateRating"}} {{/each}}
จากนั้นใช้ชื่อนั้นเพื่อส่งการดำเนินการ:
// app/components/star-rating.js export default Ember.Component.extend({ item: null, rating: 0, (...) actions: { set: function(newRating) { var item = this.get('item'); this.sendAction('setAction', { item: this.get('item'), rating: newRating }); } } });
สุดท้าย การดำเนินการจะได้รับการจัดการต้นน้ำ โดยผู้ควบคุมหรือเส้นทาง และนี่คือตำแหน่งที่การจัดอันดับของรายการได้รับการอัปเดต:
// app/routes/player.js export default Ember.Route.extend({ actions: { updateRating: function(params) { var skill = params.item, rating = params.rating; skill.set('score', rating); return skill.save(); } } });
เมื่อสิ่งนี้เกิดขึ้น การเปลี่ยนแปลงนี้จะแพร่กระจายลงไปตามการเชื่อมโยงที่ส่งผ่านไปยังองค์ประกอบ star-rating
และจำนวนดาวเต็มที่แสดงจะเปลี่ยนแปลงตามไปด้วย
ด้วยวิธีนี้ การกลายพันธุ์จะไม่เกิดขึ้นในส่วนประกอบ และเนื่องจากส่วนเฉพาะของแอพเพียงส่วนเดียวคือการจัดการการดำเนินการในเส้นทาง ความสามารถในการนำกลับมาใช้ใหม่ของส่วนประกอบจึงไม่ได้รับผลกระทบ
เราสามารถใช้องค์ประกอบเดียวกันสำหรับทักษะฟุตบอลได้เช่นกัน:
{{#each player.skills as |skill|}} {{star-rating item=skill rating=skill.score setAction="updateSkill"}} {{/each}}
คำพูดสุดท้าย
สิ่งสำคัญคือต้องสังเกตว่าข้อผิดพลาดบางอย่าง (ส่วนใหญ่?) ที่ฉันเคยเห็นคนทำ (หรือทำด้วยตัวเอง) รวมถึงข้อผิดพลาดที่ฉันเขียนเกี่ยวกับที่นี่ กำลังจะหายไปหรือบรรเทาลงอย่างมากในช่วงต้นของซีรีส์ 2.x ของ Ember.js
สิ่งที่เหลืออยู่ได้รับการแก้ไขโดยคำแนะนำของฉันด้านบน ดังนั้นเมื่อคุณพัฒนาใน Ember 2.x คุณจะไม่มีข้อแก้ตัวใด ๆ ที่จะทำผิดพลาดอีก! หากคุณต้องการให้บทความนี้เป็น pdf ไปที่บล็อกของฉันและคลิกลิงก์ที่ด้านล่างของโพสต์
เกี่ยวกับฉัน
ฉันมาที่ front-end world กับ Ember.js เมื่อสองปีก่อน และฉันอยู่ที่นี่เพื่ออยู่ต่อ ฉันตื่นเต้นกับ Ember มากจนเริ่มเขียนบล็อกอย่างเข้มข้นทั้งในโพสต์ของแขกและในบล็อกของฉันเอง รวมถึงการนำเสนอในที่ประชุม ฉันยังเขียนหนังสือ Rock and Roll with Ember.js สำหรับทุกคนที่ต้องการเรียนรู้ Ember คุณสามารถดาวน์โหลดบทตัวอย่างได้ที่นี่