JavaScript - מה זה קישור דו-כיווני?
קראתי הרבה ש-Backbone לא עושה קשירת שני כיוונים, אבל אני לא בדיוק מבין את המושג הזה.
האם מישהו יכול לתת לי דוגמה כיצד קישור דו-כיווני עובד בבסיס קוד MVC וכיצד הוא לא עובד עם Backbone?
תשובה #1
קישור דו-כיווני פשוט אומר ש:
- כאשר המאפיינים במודל מתעדכנים, כך גם הממשק המשתמש.
- כאשר רכיבי הממשק מתעדכנים, השינויים מועברים חזרה למודל.
ל-Backbone אין מימוש "מובנה" של #2 (למרות שאפשר בהחלט לעשות זאת באמצעות מאזיני אירועים). מסגרות אחרות כמו Knockout מחברות קישוריות דו-כיוונית באופן אוטומטי.
ב-Backbone, ניתן להשיג בקלות את #1 על ידי קישור מתודת ה-"render" של התצוגה לאירוע ה-"change" של המודל שלה. כדי להשיג את #2, יש להוסיף גם מאזין ל-"change" עבור אלמנט הקלט, ולקרוא ל-model.set במטפל.
הנה Fiddle עם קישוריות דו-כיוונית מוגדרת ב-Backbone.
תשובה #2
קישור דו-כיווני משמעותו שכל שינוי הקשור לנתונים שמשפיע על המודל מועבר מיד אל התצוגה (או התצוגות) התואמת, וכל שינוי המתבצע בתצוגה (למשל, על ידי המשתמש) משתקף מיד במודל התחתון. כאשר נתוני האפליקציה משתנים, גם ממשק המשתמש משתנה, ולהפך.
זהו קונספט מאוד יציב לבנות עליו יישום ווב, כי הוא הופך את ההפשטה של ה"מודל" למקור נתונים בטוח ואטומי לשימוש בכל מקום בתוך היישום. נניח שמודל, הקשור לתצוגה, משתנה, אז החלק התואם של ממשק המשתמש (התצוגה) ישקף זאת, לא משנה מה. והחלק התואם של ממשק המשתמש (התצוגה) יכול לשמש בבטחה כאמצעי לאיסוף קלט/נתונים מהמשתמש, כדי לשמור שהנתונים של היישום יהיו מעודכנים.
מימוש טוב של קישור דו-כיווני צריך כמובן לעשות את החיבור הזה בין מודל לבין כמה תצוגות ככל האפשר פשוט, מנקודת המבט של המפתח.
ואז זה די לא נכון לומר ש-Backbone אינו תומך בקישור דו-כיווני: אף כי זו אינה אפשרות מרכזית במסגרת, ניתן לבצע זאת די בקלות באמצעות Events של Backbone. זה עולה רק כמה שורות קוד מפורשות במקרים הפשוטים; ויכול להפוך למסוכן למדי עבור קישורים מורכבים יותר. הנה מקרה פשוט (קוד לא נבדק, נכתב בחפיסה רק לצורך המחשה):
Model = Backbone.Model.extend
defaults:
data: ''
View = Backbone.View.extend
template: _.template("Edit the data: <input type='text' value='<%= data %>' />")
events:
# Listen for user inputs, and edit the model.
'change input': @setData
initialize: (options) ->
# Listen for model's edition, and trigger UI update
@listenTo @model, 'change:data', @render
render: ->
@$el.html @template(@model.attributes)
@
setData: (e) =>
e.preventDefault()
@model.set 'data', $(e.currentTarget).value()
model: new Model()
view = new View {el: $('.someEl'), model: model}
זו דוגמה די טיפוסית בתבנית באפליקציית Backbone גולמית. כפי שניתן לראות, זה דורש כמות לא קטנה של קוד (די סטנדרטי).
AngularJS וכמה חלופות אחרות (Ember, Knockout…) מספקות קשירה דו-כיוונית כתכונה מרכזית. הן מוסיפות שכבת הפשטה על רבים מהמקרים הקיצוניים תחת DSL מסוים, ועושות את מיטב יכולתן לשלב את הקשירה הדו-כיוונית בתוך האקוסיסטם שלהן. הדוגמה שלנו תיראה משהו כזה עם AngularJS (קוד לא נבדק, ראו למעלה):
<div ng-app="app" ng-controller="MainCtrl">
Edit the data:
<input name="mymodel.data" ng-model="mymodel.data">
</div>
angular.module('app', [])
.controller 'MainCtrl', ($scope) ->
$scope.mymodel = {data: ''}
די קצר!
אבל, היו ערים לכך שכמה תוספי קישור דו-כיווני מלאים קיימים בפועל גם עבור Backbone (בסדר גולמי, סובייקטיבי של מורכבות פוחתת): Epoxy, Stickit, ModelBinder…
דבר מגניב אחד עם אפוקסי, למשל, הוא שהוא מאפשר לך להצהיר על הקישורים שלך (תכונות המודל <-> אלמנט ה-DOM של התצוגה) או בתוך התבנית (DOM), או בתוך מימוש התצוגה (JavaScript). יש אנשים שממש לא אוהבים להוסיף "הוראות" ל-DOM/תבנית (כמו המאפיינים ng-* הנדרשים על ידי AngularJS, או המאפיינים data-bind של אמבר).
לקיחת אפוקסי כדוגמה, אפשר לעבד מחדש את יישום ה-Backbone הגולמי למשהו כזה (…):
Model = Backbone.Model.extend
defaults:
data: ''
View = Backbone.Epoxy.View.extend
template: _.template("Edit the data: <input type='text' />")
# or, using the inline form: <input type='text' data-bind='value:data' />
bindings:
'input': 'value:data'
render: ->
@$el.html @template(@model.attributes)
@
model: new Model()
view = new View {el: $('.someEl'), model: model}
בסך הכל, כמעט כל מסגרת JS "ראשית" תומכת בקישור דו-כיווני. חלק מהן, כמו Backbone, דורשות מעט עבודה נוספת כדי שזה יעבוד חלק, אבל אלו הן אותן מסגרות שאינן מחייבות דרך מסוימת לעשות זאת, מלכתחילה. אז זה באמת עניין של מצב הרוח שלך.
בנוסף, ייתכן שתתעניין ב-Flux, ארכיטקטורה שונה עבור יישומי ווב שמקדמת חיבור חד כיווני דרך תבנית מעגלית. היא מבוססת על הרעיון של עיבוד מחדש מהיר והוליסטי של רכיבי ממשק המשתמש עם כל שינוי בנתונים כדי להבטיח קוהרנטיות ולהקל על ההבנה של הקוד/זרימת הנתונים. באותו המגמה, ייתכן שתרצה לבדוק את המושג MVI (מודל-תצוגה-כוונה), לדוגמה Cycle.
תשובה #3
ל-McGarnagle יש תשובה נהדרת, ותרצה לקבל את שלו, אבל חשבתי שאני אציין (מכיוון ששאלת) איך עובדת התקשרות הנתונים.
זה מיושם בדרך כלל על ידי הפעלת אירועים בכל פעם שמתבצעת שינוי בנתונים, מה שגורם למאזינים (למשל הממשק הגרפי) להתעדכן.
קישור דו-כיווני פועל על ידי ביצוע זה פעמיים, עם קצת זהירות כדי לוודא שלא תמצאו את עצמכם תקועים בלולאת אירוע (שבו העדכון מהאירוע גורם לאירוע נוסף להתבצע).
הייתי עומד לשים את זה בתגובה, אבל זה התחיל להיות די ארוך...
