问题
This is a betting game, made in backbone. I have a bounty of 100 to help me refactor it into a marionette based application.
I am unsure where to start - in terms of reconfiguring the models, how to swap the views out to make them regions.
I believe the steps would be to start with creating a new marionette application and router.
var app = Marionette.Application.extend({
initialize: function(options) {
console.log('My container:', options.container);
}
});
var app = new app({container: '#app'});
//router
var MyRouter = Marionette.AppRouter.extend({
appRoutes: {
"some/route": "someMethod"
},
routes : {
"some/otherRoute" : "someOtherMethod"
},
someOtherMethod : function(){
// do something here.
}
});
Then create a few regions and layouts to manage old backbone views.
//regions
MyApp.addRegions({
bankValue: "#bankvalue",
bitValue: "#bitvalue"
});
Then convert the old backbone views to Marionette's ItemViews and CompositeViews.
//compositeview
var CompositeView = Marionette.CompositeView.extend({
template: "#personalbank"
});
new CompositeView({
model: userModel,
collection: someCollection
});
Here is the latest js fiddle.
//UserBankModel
var UserBankModel = Backbone.Model.extend({
defaults: {
chips: 200
},
initialize: function() {
console.log("UserBankModel initialize");
this.on("change:chips", function(model) {
var chips = model.get("chips"); // 23232
console.log("Changed my chips to " + chips);
});
}
});
//UserBankView
var UserBankView = Backbone.View.extend({
initialize: function() {
console.log("UserBankView initialize");
this.render();
},
render: function(value) {
this.$el.html(value);
}
});
//BitcoinModel
var BitcoinModel = Backbone.Model.extend({
defaults: {
currentValue: 0,
lockedValue: 0
},
initialize: function() {
console.log("BitcoinModel initialize");
this.on("change:currentValue", function(model) {
var currentValue = model.get("currentValue"); // 494
console.log("Changed my currentValue to " + currentValue);
});
},
getBitcoinValue: function(callback) {
/*
Backbone.ajax({
dataType: 'json',
url: "https://api.bitcoinaverage.com/ticker/USD",
crossDomain: true,
success: function(data) {
callback(data);
}
});
*/
json= {
bid: 320,
ask: 444
};
var mediumValue = (json.bid + json.ask) / 2;
callback(mediumValue);
}
});
//BitcoinView
var BitcoinView = Backbone.View.extend({
initialize: function() {
console.log("BitcoinView initialize");
this.render();
},
render: function(value) {
this.$el.html(value);
}
});
var App = Backbone.Model.extend({
initialize: function() {
var that = this;
this.userBankModel = new UserBankModel();
this.userBankView = new UserBankView({
el: $("#bankvalue")
});
this.bitcoinModel = new BitcoinModel();
this.bitcoinView = new BitcoinView({
el: $("#bitvalue")
});
//setInterval(function() {
//get val of bitcoin every second
that.bitcoinModel.getBitcoinValue(function(mediumVal) {
//set bit coin model
that.bitcoinModel.set({
currentValue: mediumVal
});
//render the bit coin value
that.bitcoinView.render(that.bitcoinModel.get("currentValue"));
});
//}, 1000);
//render users chips
this.userBankView.render(this.userBankModel.get("chips"));
},
currentBitcoinValue: 0,
startBet: function(state) {
console.log("start timer");
this.state = state;
//get locked value of bitcoin for the game
var stashValue = this.bitcoinModel.get("currentValue");
//set bit coin model with locked value
this.bitcoinModel.set({
lockedValue: stashValue
});
var initialTimer = 5;
var Timer = {
i: initialTimer,
onTimer: function() {
var that = this;
document.getElementById('timer').innerHTML = Timer.i;
Timer.i--;
if (Timer.i < 0) {
app.gameResult();
Timer.i = initialTimer; //reset
} else {
setTimeout(Timer.onTimer, 1000);
}
}
};
Timer.onTimer();
},
gameResult: function() {
console.log("whats the result then");
console.log("this.state", this.state);
var lockedValue = this.bitcoinModel.get("lockedValue");
var currentValue = this.bitcoinModel.get("currentValue");
console.log("lockedValue>>", lockedValue);
console.log("currentValue>>", currentValue);
var result = "loss";//lose by default
//locked value was higher
if (
this.lockedValue > this.currentValue && this.state["bet"] == "high" ||
this.lockedValue < this.currentValue && this.state["bet"] == "low"
) {
result = "win";//win if conditions are met
}
//get current value of user chips
var newVal = this.userBankModel.get("chips");
if (result == "win") {
console.log("WIN -- you get chips");
newVal += this.state["wager"];
} else {
console.log("LOSS -- you loose chips");
newVal -= this.state["wager"];
}
//won or lost chips -- set new chip value
this.userBankModel.set({
chips: newVal
});
//render new user chips
this.userBankView.render(this.userBankModel.get("chips"));
}
});
var app = new App();
var FormView = Backbone.View.extend({
el: '#wager-form',
events: {
"submit": "doMethod"
},
doMethod: function(e) {
e.preventDefault();
var obj = [];
this.$el.find('input[name]').each(function() {
obj[this.name] = this.value;
});
//start bet
app.startBet(obj);
}
});
var form = new FormView();
I would like to know more about the best practice in using Marionette with backbone. Why use Marionette, what is the advantage?
Is it a simple case of refactoring the following example. Or does a Marionette based method work more like a collection?
var App = Backbone.Model.extend({
initialize: function() {
//standard app
}
});
But would this be the way to refactor the App model to use Marionette?
var App = Marionette.Application.extend({
initialize: function(options) {
console.log('My container:', options.container);
//invoke other models
this.otherModel1 = new OtherModel1();
this.otherView1= new OtherView1({
el: $("#selector1")
});
}
});
//add the selectors in one place?
MyApp.addRegions({
someRegion: "#some-div",
anotherRegion: "#another-div"
});
// Although applications will not do anything
// with a `container` option out-of-the-box, you
// could build an Application Class that does use
// such an option.
var app = new App({container: '#app'});
This is the structure of my application. How would I refactor it properly to use marionette
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>backbone js</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0-beta1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/json2/20150503/json2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.js/1.2.3/backbone-min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/backbone.marionette/2.4.4/backbone.marionette.js"></script>
</head>
<body>
Content of the document......
<div id="app"></div>
<div id="select1"></div>
<div id="select2"></div>
<script>
//myModel1
var MyModel1 = Backbone.Model.extend({
initialize: function() {
console.log("myModel1 initialize");
}
});
//myView1
var MyView1 = Backbone.View.extend({
initialize: function() {
console.log("myView1 initialize");
this.render();
},
render: function(value) {
this.$el.html(value);
}
});
//myModel2
var MyModel2 = Backbone.Model.extend({
initialize: function() {
console.log("myModel2 initialize");
}
});
//myView2
var MyView2 = Backbone.View.extend({
initialize: function() {
console.log("myView2 initialize");
this.render();
},
render: function(value) {
this.$el.html(value);
}
});
//the core that invokes and bridges the other models.
var App = Backbone.Model.extend({
initialize: function() {
var that = this;
this.myModel1 = new MyModel1();
this.myView1 = new MyView1({
el: $("#select1")
});
this.myModel2 = new MyModel2();
this.myView2 = new MyView2({
el: $("#select2")
});
}
});
var app = new App();
/*ok marionette stuff*/
var MyApp = Marionette.Application.extend({
initialize: function(options) {
console.log(options.container);
}
});
var myApp = new MyApp({container: '#app'});
</script>
</body>
</html>
Ok so would the code kind of look like this? Where I pump the models into the options variable?
MyApp.addInitializer(function(options){
// do useful stuff here
var otherView1= new OtherView1({
model: options.otherModel1
});
MyApp.mainRegion.show(otherView1);
});
MyApp.addInitializer(function(options){
new MyAppRouter();
Backbone.history.start();
});
this is my current application - but I am unsure how to structure it with marionette moving forward?
Latest fiddle of the entire core application.
Ok so, I have my application with standard backbone like this..
with a core Model that invokes and bridges the other models. Something like this.
Old backbone way
var App = Backbone.Model.extend({
initialize: function() {
this.myModel1 = new MyModel1();
this.myView1 = new MyView1({
el: $("#select"),
model: this.myModel1
});
this.myModel2 = new MyModel2();
this.myView2 = new MyView2({
el: $("#select"),
model: this.myModel2
});
}
});
so is Marionette supposed to work like this?
App.addInitializer(function(options) {
App.myModel1 = new MyModel1();
App.myView1 = new MyView1({
el: $("#select1"),
model: App.myModel1
});
App.myModel2 = new MyModel2();
App.myView2 = new MyView2({
el: $("#select2"),
model: App.myModel2
});
});
and what about regions.. Do I stop using el: selectors for the view and rely on regions? And if so, how?
var View1Region = Backbone.Marionette.Region.extend({
el: "#select1", // Must be defined for this syntax
// Whatever other custom stuff you want
});
var View2Region = Backbone.Marionette.Region.extend({
el: "#select2", // Must be defined for this syntax
// Whatever other custom stuff you want
});
// Use these new Region types on App.
App.addRegions({
view1Region: View1Region,
view2Region: View2Region
});
// This is equivalent to:
App.view1Region = new View1Region();
App.view2Region = new View2Region();
I've made a new jsfiddle to start structuring the marionette version.
but am I invoking it correctly, using the new composite view correctly.
//UserBankModel
var UserBankModel = Backbone.Model.extend({
defaults: {
chips: 200
},
initialize: function() {
console.log("UserBankModel initialize");
this.on("change:chips", function(model) {
var chips = model.get("chips"); // 23232
console.log("Changed my chips to " + chips);
});
}
});
var CompositeView = Marionette.CompositeView.extend({
template: "#personalbank"
});
var userBankView = new CompositeView({
model: UserBankModel
});
var MyApp = Marionette.Application.extend({
initialize: function(options) {
console.log('My container:', options.container);
this.userBankModel = new UserBankModel();
}
});
var app = new MyApp({
container: '#app'
});
app.addRegions({
bankValue: "#bankvalue",
bitValue: "#bitvalue"
});
If we focus on the view for a second, how would I refactor this in the way I was intending to.
html
<div id="list"></div>
<script type="text/template" id="list-template">
<div class="pagination">
<ul></ul>
</div>
</script>
<script type="text/template" id="item-template">
<a href="#<%= id %>"><%= id %></a>
</script>
js
var Item = Backbone.Model.extend();
var Items = Backbone.Collection.extend({
model: Item
});
var Views = {};
Views.ListItem = Backbone.Marionette.ItemView.extend({
template: "#item-template",
tagName: 'li'
});
Views.List = Backbone.Marionette.CompositeView.extend({
template: "#list-template",
itemView: Views.ListItem,
itemViewContainer: "ul"
});
var Data = [
{id: 1},
{id: 2}
];
var items = new Items(Data);
var list = new Views.List({
collection: items
});
list.render();
$("#list").html(list.el);
http://jsfiddle.net/c72Vg/168/
回答1:
A while ago the answer would have been "no", use Marionette's Application.addInitializer(function () {})
but when Marionette v3 is released that will be removed and in it's place you're expected to use events.
来源:https://stackoverflow.com/questions/35618498/marionette-backbone-js-betting-game