8 ข้อผิดพลาดที่พบบ่อยที่สุดที่นักพัฒนา Ember.js ทำ

เผยแพร่แล้ว: 2022-03-11

Ember.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.js

แผนการบรรเทาทุกข์ของ 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 คุณสามารถดาวน์โหลดบทตัวอย่างได้ที่นี่