Backbone.js click event in a Modal Reveal - javascript

I got a Modal Reveal (http://foundation.zurb.com/docs/components/reveal.html) in a template and in this modal I got a form with a button and I want to listen to this button in the view but when I click it doesn't fire anything.
here is my code :
index.html :
<body>
<div class="page">
<div id="content"></div>
</div>
</body>
tplGroups.html :
<div id="myModal" class="reveal-modal small" data-reveal>
<label>Name :</label>
<input type="text" id="inNameGroup"></input>
<label > Description :</label>
<textarea id="inDescriptionGroup"></textarea>
<button class="button right" id="btnAddGroup">Add group</button>
<a class="close-reveal-modal">×</a>
</div>
<div class="row">
<button class="button tiny right" data-reveal-id="myModal" data-reveal>Add</button>
</div>
group.js :
el: "#content",
initialize: function(){},
render:function(){
this.template = _.template(tpl.get('tplGroup'));
this.$el.html(this.template(this.model.attributes));
this.$el.i18n();
return this;
},
events:{
"click #btnAddGroup": "addGroup"
},
addGroup: function(){
...
}
I think the problem is that the view can't find the button in the el.

Event's in backbone views work using event delegation, that is when you specify an events hash backbone binds those events to the root el. In this case your problem is that the modal popup isn't actually a descendent of the root el (the plugin attaches it elsewhere in the DOM, you can inspect the element in firebug/web inspector to see this yourself).
What you can do is bind the event manually yourself, for example
render:function(){
this.template = _.template(tpl.get('tplGroup'));
this.$el.html(this.template(this.model.attributes));
this.$el.i18n();
$('#btnAddGroup').on('click', this.addGroup);
return this;
},

Even though there has already been a correct answer I would like to add that if you open the modal from within the Backbone view it returns a reference to the new element.
var modalElement = this.$('#myModal').foundation('reveal', 'open');
The element's reference can be applied to the view using the setElement() method which will create the cached $el reference and move the view's delegated events from the old element to the new one.
tplGroups.html:
<div id="myModal" class="reveal-modal small" data-reveal>
<label>Name :</label>
<input type="text" id="inNameGroup"></input>
<label > Description :</label>
<textarea id="inDescriptionGroup"></textarea>
<button class="button right" id="btnAddGroup">Add group</button>
<a class="close-reveal-modal">×</a>
</div>
<div class="row">
<button class="button tiny right" id="btnOpenModal">Add</button>
</div>
group.js:
el: "#content",
initialize: function(){},
render:function(){
this.template = _.template(tpl.get('tplGroup'));
this.$el.html(this.template(this.model.attributes));
this.$el.i18n();
return this;
},
events:{
"click #btnOpenModal": "openModal",
"click #btnAddGroup": "addGroup"
},
openModal: function(){
this.setElement(this.$('#myModal').foundation('reveal', 'open'));
},
addGroup: function(){
...
}

Related

Detect clicks inside a Div but outside of a particular child Div in VueJS

I have a page in which I have MCQ Options which looks like this:
This is the HTML Code for the options parts till now:
<div v-for="(option, index) in optionsForFrontend">
<div class="option">
<div class="radio-check-item">
<input type="radio"
name="question"
:value="index"
v-model="picked"
v-if="question.metadata.choices === 'Single'">
<input type="checkbox"
name="question"
:value="index"
v-model="picked"
v-if="question.metadata.choices === 'Multiple'">
</div>
<div class="divider">
</div>
<div class="content-item">
<vue-markdown :source="option.option"></vue-markdown>
</div>
</div>
</div>
I want to select the options by clicking on the option content. So I put a :click="functionToSelectOption" on the outer div ("option") containing checkbox and option content.
The problem is when I select the checkbox, it gets selected and the function "functionToSelectOption" gets called as well since the checkbox is inside the "option" div.
I want to be able to detect a click inside the "option" div but outside radio/checkbox div so I can call the function to toggle the option.
I mostly found similar questions under jquery tags and nothing with VueJS.
I would avoid event.stopPropagation(). All kinds of things might be listening higher up in the tree. For instance, you might want an onclick on the window to close a modal dialog if the user clicks outside the dialog. The much less radical way to do this is to look at event.target. This jsfiddle tests (event.target == event.currentTarget) so it only reacts to clicks on the parent div.
Markup
<div id="ctr">
<div v-for="(option,index) in options"
style="margin:10px;padding:10px;border:solid;border-radius:4px"
#click="parent"
>
<input type="checkbox" :name="'invidiousChoice' + index" #click='child'> {{option.label}}
</div>
</div>
JS
var vm = new Vue({
el:"#ctr",
data : {
options:[{label:'terrible option'},{label:'disastorous option'}]
},
methods: {
parent: function(event) {
if(event.target == event.currentTarget)
alert( 'parent clicked');
}
}
})
You can use event.stopPropagation() in child element.
Here is working JSFiddle Solution: Link
HTML
<div id="app">
<div #click="parent">
Parent
<div>
<input type="checkbox" #click="child">
</div>
</div>
{{message}}
JS
new Vue({
el: '#app',
data: {
message: ''
},
methods: {
parent: function() {
this.message = 'parent clicked';
},
child: function() {
event.stopPropagation()
}
}
});

Backbone.js audio control

I have a Backbone view, it uses an html template, placed on the page:
<script type="text/template" id="webphone-template">
<audio id="audio-ringtone" src="{% static "prime_app/assets/audio/ringtone.mp3" %}"></audio>
<div class="well">
<p class="text-muted text-center"><%= status %></p>
<div class="text-center">
<button id="btn-webphone-answer" class="btn btn-success">
<i class="fa fa-phone"></i>
</button>
<button id="btn-webphone-terminate" class="btn btn-danger">
<i class="fa fa-phone"></i>
</button>
</div>
</div>
</script>
My view has method ring(), which looks like this:
ring: function() {
$("#audio-ringtone").get(0).play();
}
But when this method is invoked audio doesn't play, no errors in JS console, the audio element is chosen correctly. What's the problem?
Well i dont know how your whole view works, if you add it i can modify the code, but i got it to work fairly easy. Again, i need to see your view code to see what youre doing wrong.
View = Backbone.View.extend({
template: _.template($('#webphone-template').html()),
events: {
'click #btn-webphone-answer': 'ring'
},
initialize: function(opt) {
// attach to the main body
$(opt['main']).append(this.el)
this.status = 'paused';
this.render();
},
ring: function() {
$(this.el).find('#audio-ringtone')[0].play()
},
render: function() {
$(this.el).append(this.template({status: this.status}));
return this;
}
});
new View({ main: $('body') });
works: http://jsfiddle.net/hLero5rd/
Finally, there was the following problem: audio-tag is in my view's element, when i call render(), it completely replaces all the HTML inside element, so if there is audio-element it just gets removed and the sound doesn't play anymore.

AngularJS popover: hide popover template on mouse out

I am using AngularJS' ui-bootstrap module. Here's my markup:
<button class="btn btn-default btn-sm" type="button"
popover-template="dynamicPopover.templateUrl"
popover-trigger="click" id="custom_overview"
popover-placement="bottom">Custom</button>
Here's my controller:
$scope.dynamicPopover = {
templateUrl : '../static/templates/popup-templates/datepicker.html'
};
Here's my popover template:
<div class="row" id="datepicker-container">
<div class="col-sm-12 clearfix">
<div class="col-sm-12">
<span class="heading">From:</span>
<input ng-model="timedata.fromDate" type="text" id="fromDate"
class="form-control" datepicker-popup="dd-MM-yyyy"
is-open="fromOpen.isOpen" ng-click="fromOpen.isOpen = true" placeholder="dd-mm-yyyy">
</div>
<div class="col-sm-12" style="margin-top:5px">
<span class="heading">To:</span>
<input ng-model="timedata.toDate" type="text" id="toDate"
class="form-control" datepicker-popup="dd-MM-yyyy"
is-open="toOpen.isOpen" ng-click="toOpen.isOpen = true" placeholder="dd-mm-yyyy">
<div class="error"
ng-show="timedata.toDate <= timedata.fromDate && timedata.fromDate && timedata.toDate">
<span>'To' date cannot be less than 'From' date.</span>
</div>
</div>
</div>
<div class="col-sm-12" id="submit-button">
<button class="btn btn-primary" ng-click="setInterval('custom')"
ng-disabled="timedata.toDate <= timedata.fromDate || !timedata.toDate || !timedata.fromDate">
Submit
</button>
</div>
</div>
As you can see, I am populating a popover with a popover template which contains a form. Here's a screenshot:
This popover opens up when I click on the 'Custom' button. Now, I want this popover to hide when I take the mouse away from the template and the 'Custom' tab. How can I do it?
In short,
replacing popover-trigger="click" by popover-trigger="'mouseleave : click'" should work for you.
For more understanding,
As per uib-popover documentation, both popover open and close triggers will be enabled by default with the popover-trigger attribute(only if you want to close and open on same event).
For example:
popover-trigger="'mouseenter'" This by default should open the popover on mouseover and close the popover on mouseleave
popover-trigger="'click'" - This will show and hide on clicks
In your case(show and close on different events), popover-trigger attribute should contain both events in order to work.
popover-trigger="'mouseleave : click'" This should work. Here first and second values represents hide and show triggers respectively.

Why is the content of my contenteditable div disappearing?

The code:
post_page.js:
Template.postPage.events({
// Updating a post
'submit form': function(e) {
e.preventDefault();
var post = {
title: $(e.target).find('[name=title]').val(),
content: $(e.target).find('[name=content]').val()
};
Posts.update(this._id, {$set: post});
},
'click .move-up': function(e) {
// Moving up a post
e.preventDefault();
var prevPost = Posts.findOne({position: this.position - 1});
if (prevPost) {
Posts.update(prevPost._id, {$set: {position: prevPost.position + 1}});
Posts.update(this._id, {$set: {position: this.position - 1}});
}
},
(...)
Template.postPage.rendered = function() {
// Plugin to turn the text area into a contenteditable div
var editor;
$(function() {
editor = new Simditor({
textarea: $("#input-content"),
placeholder: "...",
pasteImage: true,
toolbar: ["title", "bold", "italic", "underline", "link", "image", "indent", "outdent"],
upload: {
url: "/upload"
}
});
post_page.html:
<template name="postPage">
<div class="posts">
<div class="post">
<div class="post-content">
<span>title: {{title}}, position: {{position}}</span>
<a class="move-up" href="javascript:;">Move Up</a>
<a class="move-down" href="javascript:;">Move Down</a>
See Post
<a class="save-file" href="javascript:;">Save Post</a>
</div>
</div>
</div>
<form class="form" role="form">
<div class="form-group">
<label for="exampleInputEmail1">Title</label>
<input name="title" type="text" class="form-control" id="exampleInputEmail1" placeholder="Enter email" value="{{title}}">
</div>
<div class="form-group">
<label for="exampleInputPassword1">Content</label>
<textarea name="content" class="form-control" rows="3">{{content}}</textarea>
</div>
<button type="submit" class="btn btn-default submit">Submit</button> </form> </template>
Is a single page app and everything works but for some reason the content of the contenteditable div disappears if I move up a post that isn't the one currently being displayed (the content in textarea remains and it comes back if I re-render the page):
What could be causing this? How to fix it?
Moving the post up/down causes the template to re-render completely and I suspect that because the simditor expects the DOM to persist, it either doesn't re-run on rendered or runs before Meteor's preserve-inputs package has repopulated the textarea.
You can try to work around the problem (until Meteor gets the Blaze templating engine up) by wrapping your re-rendering sensitive area (at least the textarea and possibly the complete DOM generated by simditor) in {{#constant}}. If you know the exact DOM elements you want to preserve, then you can also use preserve to prevent them from being re-rendered.

bootstrap popover form ( ajax)

I am in the middle of implementing a feature.
objective :
to have a popover form with ajax request .
bootstrap popover
NOTE : previously i tried to achive the same with the bootstrap editables
but due to the fact that I don't want data(entered in popover) to be shown on page . (which editables are for) .
So ,
with current method (jsfiddle)
ISSUE :
when I am clicking on the popover to enter data inside the from popover disappears.
i am searching for a jquery fix . ( something with event propagation will do )
my code :
<div class="box-icon" >
<div class="popover-markup">
<i class="icon-plus-sign"></i>
<div class="head hide">Enter Email<i class="icon-remove" style="margin-left: 120px;"></i></div>
<div class="content hide">
<input type="text" placeholder="Type email address">
<button type="submit" class="btn">Submit</button>
</div>
<div class="footer hide">test</div>
</div>
</div>
and my scripts are :
$( document ).ready(function() {
$('.popover-markup > .trigger').popover({
html : true,
title: function() {
return $(this).parent().find('.head').html();
},
content: function() {
return $(this).parent().find('.content').html();
}
});
// Attach click handler to document
$(document).bind('click', function (e) {
$(".popover-markup").popover('hide');
});
// Dont hide when I click anything inside #container
$('.popover-markup').bind('click', function(e) {
e.stopPropagation();
});
});

Categories