I'm having issues rendering a modal popup dialog as a template with Underscore and Backbone on a Django website, otherwise it works as a standalone single page app. Why would that be?
Here is a snippet of the template:
<script type="text/template" id="popup-template">
<div class="modal sector-popup" style="background-color:#f5f5f5; visibility:visible;">
<div class="modal-header" style="background-color:#FFFFFF">
<input type="image" class="pull-right" id="closebtn" src="../media/x-button.png" data-dismiss="modal">
...
</div>
</script>
And here is where it is used in the website:
window.FormPopup = Backbone.View.extend({
template: _.template($('#popup-template').html()),
events: {
"dblclick .sector-label" : "edit",
"keypress .sector-label-edit input" : "setLabel"
},
render: function() {
var view = this;
this.$el.html(this.template(this.model.toJSON()));
...
},
});
Related
I have a Meteor app that has a template loaded.
Inside that template I have a button.
When the button is clicked, I want the app to render or switch to another template which also happens to be a modal.
I can't figure out how to render another template from the click event function.
Any ideas? Here is my code below.
search.html
<template name='search'>
<button class='btn btn-primary' id='showModalButton'>Show Modal</button>
</template>
<template name='searchCustomer'>
<!-- set up the modal to start hidden and fade in and out -->
<div id="myModal" class="modal fade">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Modal title</h4>
</div>
<!-- dialog body -->
<div class="modal-body">
My modal body
<div class="modal-footer"><button type="button" class="btn btn-primary">OK</button></div>
</div>
</div>
</div>
</template>
search.js
Template.search.onRendered(function() {
'click #showModalButton': {
// WHAT DO I DO HERE TO RENDER OR CALL THE
// SEARCHCUSTOMER TEMPLATE WITH THE MODAL?
}
});
Template.searchCustomer.onRendered(function() {
$("#myModal").on("show", function() {
$("#myModal a.btn").on("click", function(e) {
$("#myModal").modal('hide');
});
});
$("#myModal").on("hide", function() {
$("#myModal a.btn").off("click");
});
$("#myModal").on("hidden", function() {
$("#myModal").remove();
});
$("#myModal").modal({
"backdrop" : "static",
"keyboard" : true,
"show" : true // show the modal immediately
});
});
I haven't tried this, but I believe you can use a template helper and a Session variable to accomplish this.
<body>
{{> search }}
{{#if showModal }}
{{> searchCustomer }}
{{/if}}
</body>
and then in your js file...
Template.search.helpers({
'showModal': function(){
return Session.get('showModal');
}
'click #showModalButton': function(){
Session.set('showModal', true);
}
);
The searchCustomer template will only render when the 'showModal' Session variable is true.
I have a side view list and when one of the item in the list is clicked I show the corresponding view
My code is as follows:
VIEW
app.View.BrandSidePanelView = Backbone.View.extend({
tagName: 'div',
template: _.template($('#brand-side-panel').html()),
template_brand: _.template($('#brand-create').html()),
template_offer: _.template($('#offer-create').html()),
initialize: function() {
this.render();
},
events: {
'click .bra-main': 'showBrandCreateView',
'click .bra-off': 'showOfferCreate',
'click .bra-cmgn': 'showCampaignCreate'
},
showBrandCreateView: function(e) {
e.preventDefault();
this.reset();
$('.crt-cnt').html(this.template_brand());
},
showOfferCreate: function(e){
e.preventDefault();
this.reset();
$('.crt-cnt').html(this.template_offer());
},
render: function() {
$('.crt-cnt').html(this.template_brand());
var $el = $(this.el);
$el.html(this.template());
return $(this.el);
},
reset: function(){
$('.crt-cnt').empty();
}
});
HTML
<div class="list-group">
<div class="list-group-item bra-main"><i class="fa fa-angle-double-right"></i> <fmt:message key="brand" /></div>
<div class="list-group-item bra-off"><i class="fa fa-angle-double-right"></i> <fmt:message key="brand.offer" /></div>
<div class="list-group-item bra-cmgn"><i class="fa fa-angle-double-right"></i> <fmt:message key="brand.campaign" /></div>
</div>
Everything here is static. Nothing is fetched from the server. I am very new to backbone. The current code works but wants to know if I am doing it the right way.
If your side view list won't change in time, it's ok to do it like this, it's just a sort of static menu.
But if the elements in the list could change, you must wrap it in a View and fetch the elements from the server
var LandingView = Backbone.View.extend({
initialize: function() {
console.log('Landing View has been initialized');
this.render();
},
template: Handlebars.compile($('#landingPage').html()),
render: function() {
this.$el.html(this.template);
},
events: {
// I want to render the subview on click
'click .btn-login' : 'renderlogin',
},
renderlogin: function() {
// Is this the right way to instantiate a subview?
var loginpage = new LoginView({ el: $('#modal-content') });
}
});
And my next view, which basically just empties the $('#modal-content') element...
var LoginView = Backbone.View.extend({
initialize: function() {
this.render();
console.log("login view initialized");
},
template: Handlebars.compile($('#loginPage').html()),
render: function() {
this.delegateEvents();
this.$el.html(this.template);
},
events: {
// this is where things get super confusing...
// Upon clicking, LoginView gets re-initialized and
// subsequent clicks are called for each number of times
// the view is initialized.
'click .js-btn-login' : 'login'
},
login: function(e) {
e.preventDefault();
var self = this;
console.log($(this.el).find('#userSignIn #userEmail').val());
console.log($(this.el).find('#userSignIn #userPassword').val());
}
});
My templates:
LANDING PAGE:
<script type="text/x-handlebars-template" id="landingPage">
<div>
<div class="auth-wrapper">
<div class="logo">
<img src="img/login/logo-landing.png"/>
</div>
<div class="to-auth-buttons-wrapper">
<a class="btn-to-auth btn-signup" href="#">Sign Up</a>
<a class="btn-to-auth btn-login" href="#">Log In</a>
</div>
</div>
</div>
</script>
LOGINPAGE:
<script type="text/x-handlebars-template" id="loginPage">
<div>
<div class="header">
Back
</div>
<div class="auth-wrapper">
<div class="logo">
<img src="img/login/logo-landing.png"/>
</div>
<form method="post" id="userSignIn">
<input class="form-control input-signin" type="text" name="useremail" placeholder="Email" id="userEmail" value="tester">
<input class="form-control input-signin" type="password" name="userpass" placeholder="Password" id="userPassword">
<button class="btn-to-auth btn-login js-btn-login">Log In</button>
</form>
</div>
</div>
</script>
My goal:
From within LandingView, upon clicking .btn-login, render LoginView.
From within LoginView, upon clicking .js-btn-login, console.log
contents of form
Problems:
In LoginView, upon clicking .js-btn-login, I see that the initialize function is called again.
In LoginView, I can't use jquery to get the values inside of $('#userSignIn #userEmail').val() and $('#userSignIn #userEmail').val() because they aren't there on render. I see the initial hardcoded value ( input[value="tester"]) but this is all it sees.
My question:
How do I get the view to stop reinitializing on an event firing and how do I get the values in my DOM after rendering?
I am trying to create a modal view and have a base class that all modals need and then extending it for more specific functionality.
PlanSource.Modal = Ember.View.extend({
isShowing: false,
hide: function() {
this.set("isShowing", false);
},
close: function() {
this.set("isShowing", false);
},
show: function() {
this.set("isShowing", true);
}
});
PlanSource.AddJobModal = PlanSource.Modal.extend({
templateName: "modals/add_job",
createJob: function() {
var container = $("#new-job-name"),
name = container.val();
if (!name || name == "") return;
var job = PlanSource.Job.createRecord({
"name": name
});
job.save();
container.val("");
this.send("hide");
}
});
I render it with
{{view PlanSource.AddJobModal}}
And have the view template
<a class="button button-green" {{action show target=view}}>+ Add Job</a>
{{#if view.isShowing}}
<div class="modal-wrapper">
<div class="overlay"></div>
<div class="dialog box box-border">
<div class="header">
<p class="title">Enter a job name.</p>
</div>
<div class="body">
<p>Enter a name for your new job.</p>
<input type="text" id="new-job-name" placeholder="Job name">
</div>
<div class="footer">
<div class="buttons">
<a class="button button-blue" {{action createJob target=view}} >Create</a>
<a class="button" {{action close target=view}}>No</a>
</div>
</div>
</div>
</div>
{{/if}}
The problem is that when I click the button on the modal dialog, it gives me an "action createJob" can not be found. Am I extending the objects incorrectly because it works if I put the createJob in the base Modal class.
Fixed
There was an issue somewhere else in my code. The name got copied and so it was redefining it and making the method not exist.
I am having problems getting my backbone.js view events to fire. When I click #login-button nothing is happening.
I am also using iCanHaz (http://icanhazjs.com/) to load the templates.
Here is my javascript:
$(function() {
var router = new App.Router;
Backbone.history.start();
});
App.Router = Backbone.Router.extend({
routes: {
"login": "login"
},
login: function() {
var view = new App.Views.LoginView;
}
});
App.Views.LoginView = Backbone.View.extend({
el: '#login',
initialize: function() {
_.bindAll(this, 'render', 'validateLogin');
this.render();
},
render: function() {
App.Stage.html(ich.loginView());
},
events: {
'click button#login-button' : 'validateLogin'
},
validateLogin: function(event) {
console.log("validateLogin fired.");
}
});
Here is my markup (using ICanHaz.js):
<script id="loginView" type="text/html">
<div data-role="page" id="login" class="container">
<div class="hero-unit">
<div class="row-fluid">
<div class="span12">
<div class="form-horizontal">
<fieldset>
<legend>Please login to continue</legend>
<div class="control-group">
<label class="control-label" for="username">Username</label>
<div class="controls">
<input type="text" class="input-xlarge" id="username">
</div>
</div>
<div class="control-group">
<label class="control-label" for="password">Password</label>
<div class="controls">
<input type="password" class="input-xlarge" id="password">
</div>
</div>
<div class="form-actions">
<button id="login-button" class="btn btn-primary btn-large">Login</button>
</div>
</fieldset>
</div>
</div>
</div>
</div>
</div>
</script>
I figured it out. Backbone was binding the events to the el before it was created. In the callback for the asynchronous iCanHaz call, I used this.setElement('#login') and it worked perfectly. From the backbone.js documentation:
setElement [view.setElement(element)]
"If you'd like to apply a Backbone view to a different DOM element, use setElement, which will also create the cached $el reference and move the view's delegated events from the old element to the new one."
I believe you aren't using the View's 'el' property correctly. Try having the property reference the jQuery DOM object instead of just the ID, as follows:
App.Views.LoginView = Backbone.View.extend({
el: $('#login')
...