forms - texto - marionette fnaf
Manejar el botón de opción en Marionette js (1)
Intento crear una vista en mi aplicación que muestre preguntas de sondeo en una región de diálogo modal. Tal vez algo como esto, por ejemplo:
What is your favorite color?
>Red
>Blue
>Green
>Yellow
>Other
Submit Vote
He leído que Marionette js no admite formularios listos para usar y que se le recomienda que maneje por su cuenta.
Esa estructura de arriba, rama y hojas (pregunta y lista de opciones), me sugiere CompositeView. ¿Es eso correcto?
¿Cómo disparo un model.save () para grabar la selección? Una forma html quiere una acción. No estoy seguro de cómo conectar la acción de formulario a model.save ().
Mi borrador preliminar del código de ItemView y CompositeView está debajo. ¿Estoy en el estadio? ¿Cómo se debe ajustar?
var PollOptionItemView = Marionette.ItemView.extend({
template: Handlebars.compile(
''<input type="radio" name="group{{pollNum}}" value="{{option}}">{{option}}<br>''
)
});
var PollOptionsListView = Marionette.CompositeView.extend({
template: Handlebars.compile(
//The question part
''<div id="poll">'' +
''<div>{{question}}</div>'' +
''</div>'' +
//The list of options part
''<form name="pollQuestion" action="? what goes here ?">'' +
''<div id="poll-options">'' +
''</div>'' +
''<input type="submit" value="Submit your vote">'' +
''</form>''
),
itemView: PollOptionItemView,
appendHtml: function (compositeView, itemView, index) {
var childrenContainer = $(compositeView.$("#poll-options") || compositeView.el);
var children = childrenContainer.children();
if (children.size() === index) {
childrenContainer.append(itemView.el);
} else {
childrenContainer.children().eq(index).before(itemView.el);
}
}
});
MÁS DETALLES:
Mi objetivo realmente es crear preguntas de encuesta de forma dinámica, lo que significa que las preguntas y las opciones no se conocen en tiempo de ejecución, sino que se consultan desde una base de datos SQL a partir de entonces. Si estuvieras mirando mi aplicación, lanzaría una encuesta en tu pantalla a través de SignalR. En esencia, le estoy diciendo a tu navegador "hey, ve a obtener el contenido de la pregunta número 1 de la base de datos y muéstralos". Mi idea era que las CompositeViews son las más adecuadas para esto porque están basadas en datos. Las preguntas y las opciones correspondientes podrían ser modelos almacenados y colecciones que la plantilla CompositeView podría representar dinámicamente a pedido. Tengo la mayor parte de esto conectado y se ve bien. Mi único problema parece ser la noción de qué tipo de plantilla mostrar. ¿Una forma? ¿O debería mi plantilla simplemente colocar algunos botones de radio en la pantalla con un botón de enviar debajo y escribir algunos javascript para intentar determinar qué selección hizo el usuario? Me gustaría no utilizar un formulario en absoluto y solo usar el framework de backbone para manejar el envío. Eso me parece limpio, pero quizás no sea posible o sabio. No estoy seguro todavía.
Utilizaría el siguiente enfoque:
- Crea una colección de preguntas de tu encuesta
- Crea vistas de artículos especiales para cada tipo de pregunta
- En su CompositeView, elija el modelo itemView según su tipo
- Use una validación simple para ver si todas las preguntas han sido respondidas
- Muestra una matriz de todas las preguntas y sus resultados.
Para una implementación de ejemplo, vea este violín: http://jsfiddle.net/Cardiff/QRdhT/
Pantalla completa: http://jsfiddle.net/Cardiff/QRdhT/embedded/result/
Nota:
- Pruébalo sin responder todas las preguntas para ver la validación en el trabajo
- Verifique su consola en caso de éxito para ver los resultados
El código
// Define data
var surveyData = [{
id: 1,
type: ''multiplechoice'',
question: ''What color do you like?'',
options: ["Red", "Green", "Insanely blue", "Yellow?"],
result: null,
validationmsg: "Please choose a color."
}, {
id: 2,
type: ''openquestion'',
question: ''What food do you like?'',
options: null,
result: null,
validationmsg: "Please explain what food you like."
}, {
id: 3,
type: ''checkbox'',
question: ''What movie genres do you prefer?'',
options: ["Comedy", "Action", "Awesome", "Adventure", "1D"],
result: null,
validationmsg: "Please choose at least one movie genre."
}];
// Setup models
var questionModel = Backbone.Model.extend({
defaults: {
type: null,
question: "",
options: null,
result: null,
validationmsg: "Please fill in this question."
},
validate: function () {
// Check if a result has been set, if not, invalidate
if (!this.get(''result'')) {
return false;
}
return true;
}
});
// Setup collection
var surveyCollection = Backbone.Collection.extend({
model: questionModel
});
var surveyCollectionInstance = new surveyCollection(surveyData);
console.log(surveyCollectionInstance);
// Define the ItemViews
/// Base itemView
var baseSurveyItemView = Marionette.ItemView.extend({
ui: {
warningmsg: ''.warningmsg'',
panel: ''.panel''
},
events: {
''change'': ''storeResult''
},
modelEvents: {
''showInvalidMessage'': ''showInvalidMessage'',
''hideInvalidMessage'': ''hideInvalidMessage''
},
showInvalidMessage: function() {
// Show message
this.ui.warningmsg.show();
// Add warning class
this.ui.panel.addClass(''panel-warningborder'');
},
hideInvalidMessage: function() {
// Hide message
this.ui.warningmsg.hide();
// Remove warning class
this.ui.panel.removeClass(''panel-warningborder'');
}
});
/// Specific views
var multipleChoiceItemView = baseSurveyItemView.extend({
template: "#view-multiplechoice",
storeResult: function() {
var value = this.$el.find("input[type=''radio'']:checked").val();
this.model.set(''result'', value);
}
});
var openQuestionItemView = baseSurveyItemView.extend({
template: "#view-openquestion",
storeResult: function() {
var value = this.$el.find("textarea").val();
this.model.set(''result'', value);
}
});
var checkBoxItemView = baseSurveyItemView.extend({
template: "#view-checkbox",
storeResult: function() {
var value = $("input[type=''checkbox'']:checked").map(function(){
return $(this).val();
}).get();
this.model.set(''result'', (_.isEmpty(value)) ? null : value);
}
});
// Define a CompositeView
var surveyCompositeView = Marionette.CompositeView.extend({
template: "#survey",
ui: {
submitbutton: ''.btn-primary''
},
events: {
''click @ui.submitbutton'': ''submitSurvey''
},
itemViewContainer: ".questions",
itemViews: {
multiplechoice: multipleChoiceItemView,
openquestion: openQuestionItemView,
checkbox: checkBoxItemView
},
getItemView: function (item) {
// Get the view key for this item
var viewId = item.get(''type'');
// Get all defined views for this CompositeView
var itemViewObject = Marionette.getOption(this, "itemViews");
// Get correct view using given key
var itemView = itemViewObject[viewId];
if (!itemView) {
throwError("An `itemView` must be specified", "NoItemViewError");
}
return itemView;
},
submitSurvey: function() {
// Check if there are errors
var hasErrors = false;
_.each(this.collection.models, function(m) {
// Validate model
var modelValid = m.validate();
// If it''s invalid, trigger event on model
if (!modelValid) {
m.trigger(''showInvalidMessage'');
hasErrors = true;
}
else {
m.trigger(''hideInvalidMessage'');
}
});
// Check to see if it has errors, if so, raise message, otherwise output.
if (hasErrors) {
alert(''You haven/'t answered all questions yet, please check.'');
}
else {
// No errors, parse results and log to console
var surveyResult = _.map(this.collection.models, function(m) {
return {
id: m.get(''id''),
result: m.get(''result'')
}
});
// Log to console
alert(''Success! Check your console for the results'');
console.log(surveyResult);
// Close the survey view
rm.get(''container'').close();
}
}
});
// Create a region
var rm = new Marionette.RegionManager();
rm.addRegion("container", "#container");
// Create instance of composite view
var movieCompViewInstance = new surveyCompositeView({
collection: surveyCollectionInstance
});
// Show the survey
rm.get(''container'').show(movieCompViewInstance);
Plantillas
<script type="text/html" id="survey">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title" > A cool survey regarding your life </h3>
</div>
<div class="panel-body">
<div class="questions"></div>
<div class="submitbutton">
<button type="button" class="btn btn-primary">Submit survey!</button>
</div>
</div>
</div >
</script>
<script type="text/template" id="view-multiplechoice">
<div class="panel panel-success">
<div class="panel-heading">
<h4 class="panel-title" > <%= question %> </h4>
</div>
<div class="panel-body">
<div class="warningmsg"><%= validationmsg %></div>
<% _.each( options, function( option, index ){ %>
<div class="radio">
<label>
<input type="radio" name="optionsRadios" id="<%= index %>" value="<%= option %>"> <%= option %>
</label>
</div>
<% }); %>
</div>
</div>
</script>
<script type="text/template" id="view-openquestion">
<div class="panel panel-success">
<div class="panel-heading">
<h4 class="panel-title" > <%= question %> </h4>
</div>
<div class="panel-body">
<div class="warningmsg"><%= validationmsg %></div>
<textarea class="form-control" rows="3"></textarea>
</div>
</div >
</script>
<script type="text/template" id="view-checkbox">
<div class="panel panel-success">
<div class="panel-heading">
<h4 class="panel-title" > <%= question %> </h4>
</div>
<div class="panel-body">
<div class="warningmsg"><%= validationmsg %></div>
<% _.each( options, function( option, index ){ %>
<div class="checkbox">
<label>
<input type="checkbox" value="<%= option %>"> <%= option %>
</label>
</div>
<% }); %>
</div>
</div>
</script>
<div id="container"></div>
Actualización: ejemplo agregado de barras de control
Jsfiddle usando manubrios: http://jsfiddle.net/Cardiff/YrEP8/