Last active
September 24, 2016 23:45
-
-
Save laser/9095743 to your computer and use it in GitHub Desktop.
Marionette Best Practices
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# unless there's a really good reason to do so, a view should not be passed a reference to a preexisting DOM element | |
view = new BadPhoneInputView(el: $('#phone')) | |
# instead, write your markup as a string-property of the view prototype to be evaluated at render-time | |
class GoodPhoneInputView extends Backbone.Marionette.ItemView | |
template: "<input type='text' name='phone'><a class='submit' href='#'>submit</a>" | |
# this allows us to unit-test the view in-memory, independently of the document | |
describe 'GoodPhoneInputView', -> | |
beforeEach -> | |
@view = new GoodPhoneInputView() | |
@view.render() | |
it 'contains the elements we expect', -> | |
expect(@view.$('submit').length > 0).toBe(true) | |
# templateHelpers allow us to interpolate values into our markup at render-time | |
class GoodPhoneInputView extends Backbone.Marionette.ItemView | |
template: "<input type='text' name='phone' value='<%= phone() %>'><a class='submit' href='#'>submit</a>" | |
templateHelpers: | |
phone: () -> | |
this.name # 'this' refers to the 'attributes' property of the view's 'model' property | |
# now we can test in-memory, without appending anything to the document | |
describe 'GoodPhoneInputView', -> | |
beforeEach -> | |
@model = new Backbone.Model() | |
@view = new GoodPhoneInputView(model: @model) | |
it 'renders with a phone number, when provided', -> | |
phoneNumber = '2069991212' | |
@model.set('phone', phoneNumber, silent: true) | |
@view.render() | |
expect(@view.$('input').val()).toEqual(phoneNumber) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# definitely don't do this, because the this.$el hasn't been built | |
class EditContactView extends Backbone.Marionette.ItemView | |
initialize: (options) -> | |
@phone_input = new PhoneInputView el: @$('.phone.primary'), model: @model | |
@phone_input.render() | |
template: "<div class='phone primary'></div>" | |
# this is better ($el will be ready) - but sub-view won't be closed when parent is closed | |
class EditContactView extends Backbone.Marionette.ItemView | |
onRender: () -> | |
@phone_input = new PhoneInputView el: @$('.phone.primary'), model: @model | |
@phone_input.render() | |
template: "<div class='phone primary'></div>" | |
# do this: | |
class EditContactView extends Backbone.Marionette.Layout | |
regions: | |
phoneInput: ".phone.primary" | |
onRender: () -> | |
@phoneInput.show(new PhoneInputView(model: @model)) | |
template: "<div class='phone primary'></div>" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# to communicate between a parent a child view, pass a message bus aka a "vent" | |
class EditContactView extends Backbone.Marionette.Layout | |
initialize: () -> | |
@_vent = new Backbone.Marionette.EventAggregator() | |
@listenTo(@_vent, 'phone:updated', @_onPhoneUpdated) | |
onRender: () -> | |
@phoneInput.show(new EditPhoneNumberView(vent: @_vent)) | |
regions: | |
phoneInput: ".phone.primary" | |
template: "<div class='phone primary'></div>" | |
_onPhoneUpdated: (phoneNumber) -> | |
alert("sub view populated phone number: #{phoneNumber}") | |
# our sub-view publishes on a message bus | |
class EditPhoneNumberView extends Backbone.Marionette.ItemView | |
events: | |
'change input': '_onInputChanged' | |
initialize: (options) -> | |
@_vent = options.vent | |
template: "<input type='text' name='phone'><a class='submit' href='#'>submit</a>" | |
_onInputChanged: (e) -> | |
@_vent.trigger('phone:changed', $(e.target).val()) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# don't do this | |
class MyIncomeFormView extends Backbone.Marionette.ItemView | |
bindElements: () -> | |
@$incomeWageType = @$('#income_wage_type') | |
events: | |
'submit form': '_onFormSubmitted' | |
onRender: () -> | |
@bindElements | |
template: """ | |
<form action='#' method='POST'> | |
<input type='text' id='income_wage_type'> | |
</form> | |
""" | |
_onFormSubmitted: (e) -> | |
e.preventDefault() | |
alert(@incomeWageType.val()) | |
# use the "ui" object instead | |
class MyIncomeFormView extends Backbone.Marionette.ItemView | |
events: | |
'submit form': '_onFormSubmitted' | |
onFormSubmit: (e) -> | |
e.preventDefault() | |
console.log(@ui.incomeWageType.val()) | |
ui: | |
incomeWageType: '#income_wage_type' | |
template: """ | |
<form action='#' method='POST'> | |
<input type='text' id='income_wage_type'> | |
</form> | |
""" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# don't do this | |
class BalanceDisplayView extends Backbone.Marionette.ItemView | |
initialize: (options) -> | |
@listenTo(@model, "change:balance", this._onBalancedChanged); | |
_onBalanceChanged: () -> | |
console.log("The new balance is: #{@model.get('balance')}") | |
# use the modelEvents object instead | |
class BalanceDisplayView extends Backbone.Marionette.ItemView | |
modelEvents: | |
change: "_onBalanceChanged" | |
_onBalanceChanged: () -> | |
console.log("The new balance is: #{@model.get('balance')}") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PhoneNumberModel extends Backbone.Model | |
validate: (attributes, options) -> | |
if attributes.phone == '' | |
return 'must enter a phone number' | |
class EditPhoneNumberView extends Backbone.Marionette.ItemView | |
events: | |
'change input': '_onInputChanged' | |
'click .submit': '_onSubmitClicked' | |
initialize: (options) -> | |
@model = new PhoneNumberModel() | |
modelEvents: | |
invalid: _displayErrors | |
template: "<input type='text' name='phone'><a class='submit' href='#'>submit</a>" | |
_displayErrors: (model, error) -> | |
alert(error) | |
_onInputChanged: (e) -> | |
@model.set('phone', $(e.target).val()) | |
_onSubmitClicked: (e) -> | |
e.preventDefault() | |
alert('phone entry complete!') if @model.isValid() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# definitely don't do this, because this component relies on being passed an element that's already in the document | |
class FlashUploaderView extends Backbone.Marionette.ItemView | |
initialize: () -> | |
config = | |
uploadUrl: "/upload" | |
flash_url: "/js/vendor/swfupload/swfupload.swf" | |
button_placeholder: @$('.swfUploadButton')[0] | |
@flashUploader = new SWFUpload(settings) | |
template: "<button class='swfUploadButton'></button>" | |
# onDomRefresh callback will be fired once the view has been rendered, shown, and is in the document | |
class FlashUploaderView extends Backbone.Marionette.ItemView | |
onDomRefresh: () -> | |
config = | |
uploadUrl: "/upload" | |
flash_url: "/js/vendor/swfupload/swfupload.swf" | |
button_placeholder: @$('.swfUploadButton')[0] | |
@flashUploader = new SWFUpload(settings); | |
template: "<button class='swfUploadButton'></button>" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment