I am attempting to allow for a button to be clicked on a form and its number of votes be +=1. You'd think I could do something like idea.set({"votes": +=1}) but it doesn't seem to like that. I made an event to listen for a click on my upvote button, now I'm stuck. Can anyone help?
IdeaVoter.Views.IdeasIndex = Backbone.View.extend(
template: HandlebarsTemplates['ideas/index'],
initialize: function(){
this.collection.on('reset',this.render, this)
this.collection.on('add',this.render, this);
},
events: {
"submit #new_idea ": "createIdea",
"click #upvote": "upvote"
},
render: function(){
$(this.el).html(this.template())
this.collection.each(this.addIdea)
this.collection.each(this.upvote)
return this;
},
addIdea: function(idea){
view = new IdeaVoter.Views.Idea({model: idea})
$('#ideas').append(view.render().el)
},
upvote:function(idea){
idea.save()
}
});
I think you're looking for a simple
idea.set('votes', idea.get('votes') + 1);
You probably want to add a method to your model to hide that behind a simple idea.upvote() or the like.
Related
Context
I have a small Ember app, which, amongst other things, displays a number of connected users and, when hovering an element of the page, their names as a list.
All in all, it works quite well. The applications pulls data from a REST endpoint every two minutes, as the backend didn't allow for pushing data.
The contents of the tooltip are computed in the Controller, with a function that basically concatenate strings in various ways according to the context. Then it's bound to a data attribute of the <img> the tooltip is created on. When the View is ready and didInsertElement is fired, the tooltip is generated (if needs be) based on this data-bindattr value.
Question
When new data is pulled from the backend, everything is updated accordingly, except the tooltip content. (When browsing the page's DOM, the data-bindattr value is updated too.)
What could cause the tooltip to not refresh? Is it a case of JQuery-UI not calculating it again?
Some code
Refreshing code in the app's controller:
Monitor.ApplicationController = Ember.ArrayController.extend({
itemController: 'process',
sortProperties: ['name'],
sortAscending: true,
intervalId: undefined,
startRefreshing: function() {
var self = this;
if (self.get('intervalId')) {
return;
}
self.set( 'intervalId', setInterval(function() {
self.store.find('process');
}, 120000 ));
}
});
View: Process.hbs
<div {{bind-attr class=":inline inactive:inactive"}}>
<img {{bind-attr src=icon}} {{bind-attr data-caption=contentText}} class="caption" />
<div class="counter">{{nbUsers}}</div>
</div>
View: ProcessView
Monitor.ProcessView = Ember.View.extend({
// (...) Various stuff.
didInsertElement: function() {
this.updateTooltip();
},
updateTooltip: function() {
console.log('Inside updateTooltip!');
if (!this.$()) {return;}
if (this.get('controller').get('inactive')) {
this.$().tooltip({items: '.caption', disabled: true});
return;
}
this.$().tooltip({
items: '.caption',
tooltipClass: 'tooltip',
content: function() {
return $(this).data('caption');
},
position: {
my: 'left+15px center',
at: 'right center',
collision: 'flip'
},
show: false,
hide: false
});
}.observes('controller.inactive', 'controller.contentText')
});
Controller: ProcessController
Monitor.ProcessController = Ember.ObjectController.extend({
contentText: function() {
var tooltipContent = '';
this.get('containers').forEach(function(container) {
// Do a lot of things to tooltipContent involving:
// container.get('name')
// container.get('text')
// container.get('size')
// container.get('nbUsers')
// The data-bindattr value refreshes correctly so I cut this out for readability.
return tooltipContent;
}.property('name', 'containers.#each')
});
Edit 1:
Replaced 'containers.#each' by 'contentText' in the observer and added logging.
Here's what I think is happening:
Your tooltip library isn't observing the data-caption attribute. Meaning, when you update the attribute, you have to explicitly tell the library to update the tooltip as well. So although your attribute is updating just fine, the tooltip library isn't actually watching for those updates.
This can be remedied by calling updateTooltip, which you do, in didInsertElement. However, didInsertElement only fires once, when the element is first inserted. It's not called when the content changes.
Those two things combined are, I think, causing your problem. I think that all you need to do is have updateTooltip also observe the controller.contextText property. Then it should be called when the text updates.
So it turns out my codes declares and initialize a tooltip, but once it's done, you can't change the content the same way. Plus it adds unneeded computing anyway.
Thanks to #GJK's answer and that question, I found out what was happening. Turns out you need to set the content of the tooltip to refresh it, not recreate it.
Here is the working code for Ember integration:
Monitor.ProcessView = Ember.View.extend({
// Other stuff
didInsertElement: function() {
this.initTooltip();
},
initTooltip: function() {
if (!this.$()) {return;}
if (this.get('controller').get('inactive')) {
this.$().tooltip({items: '.caption', disabled: true});
return;
}
this.$().tooltip({
items: '.caption',
tooltipClass: 'tooltip',
content: function() {
return $(this).data('caption');
},
position: {
my: 'left+15px center',
at: 'right center',
collision: 'flip'
},
show: false,
hide: false
});
},
updateTooltip: function() {
if (!this.$()) {return;}
if (this.get('controller').get('inactive')) {
this.$().tooltip({items: '.caption', disabled: true});
return;
}
content = this.get('controller').get('contentText');
this.$().tooltip("option", "content", content);
}.observes('controller.contentText')
});
As an added bonus, you can avoid using the data attribute as a buffer now, although I'm not sure why.
I have push state enabled,
Backbone.history.start({
pushState: true
});
When i try to click on this link,
All
Its redirecting to the URL, but backbone routes is not working.
routes: {
'aspect/:id':'aspect'
},
Am i missing anything?
Update:
I tried to add it in events but still its not working,
Template:
All
View:
events: {
'click .user_aspects': 'aspects_list'
},
aspects_list: function(){
alert(2)
}
Do i need to write it in jQuery?
You need to prevent clicking and execute navigate method manually.
For example:
$('a').on('click', function (e) {
e.preventDefault();
router.navigate(e.currentTarget.getAttribute('href'), true);
})
Please have a look:
https://github.com/tbranyen/backbone-boilerplate/blob/04cd6354b0e0276442a1ddc9cdbc889924489745/app/main.js#L22
I've seen many questions posted on this topic but none of the answers/suggestions seemed to work for me. I'm fairly new to JQuery so some assistance will be much appreciated!
I've got a table with links. For some reason I can only open the dialog box for the first record (I can do this multiple times). It doesn't work for any other records.
Here's my code:
$(document).ready(function() {
var dlg=$('#ticketDetails').dialog({
title: 'Ticket Details',
resizable: true,
autoOpen:false,
modal: true,
hide: 'fade',
width:850,
height:700
});
$('#view').click(function(e) {
//testing with static record
dlg.load('displayRecord.php?id=215', function(){
dlg.dialog('open');
});
});
});
all rows in the table has the following table link:
echo '<td>View </td>';
The div to display the dialog:
<div id="ticketDetails"> </div>
I also tried sticking alert('1'); into the $('#view').click function which does not fire for other records.
In your table, each row has the same id, "view". An id is supposed to be unique for a single element on a page, so you should change this to a class:
<td>View</td>
and change your script accordingly:
$('.view').click(function(e) { ... });
Inside the event handler, you can use the event variable e to get the element that was clicked, using its target property:
$('.view').click(function(e) {
alert( $(e.target).text() );
});
I have a Rails 3.2.3 app with Backbone.js and I'm using pushState on my Backbone.history.
The Problem
When I click on a link which goes to say '/foo' to show appointment with ID: 1, then Backbone router gets to that first, which I can quickly see before Rails router takes over and complains that there is no route for /foo.
My Backbone.js code
Here is my backbone router.
window.AppointmentApp = new (Backbone.Router.extend({
routes: {
"": "index",
"foo": "foo",
"appointments": "index",
"appointments/:id": "show"
},
foo: function(){
$("#app").append("foo<br />");
},
initialize: function() {
this.appointments = new Appointments();
this.appointmentListView = new AppointmentListView({ collection: this.appointments });
this.appointmentListView.render();
},
start: function() {
Backbone.history.start({pushState: true});
},
index: function() {
$("#app").html(this.appointmentListView.el);
this.appointments.fetch();
},
show: function(id) {
console.log("Enter show");
}
}));
It should stay on the same page and attach a 'foo' to the end of the #app div, but it never does.
Backbone index viewer
window.AppointmentListView = Backbone.View.extend({
template: JST["appointments/index"],
events: {
"click .foo": function(){Backbone.history.navigate("foo");},
},
comparator: function(appointment){
return appointment.get('topic');
},
initialize: function(){
this.collection.on('reset', this.addAll, this);
},
render: function(){
this.$el.html(this.template);
this.addAll();
return this;
},
addAll: function() {
this.collection.forEach(this.addOne, this);
},
addOne: function(appointment){
var appointmentView = new AppointmentView({model: appointment});
this.$el.append(appointmentView.render().el);
}
});
app/assets/templates/appointments/Index.jst.ejs
<h1>Appointments</h1>
Say Foo
<a href=appointments/add>Add</a>
<div id="app"></div>
I was using pushState as it allows me to keep a history and the Back button functionality.
The Backbone.history.navigate doesn't call my Backbone route, it calls the Rails route instead. How do I go about fixing this?
Should I be trying to setup Backbone to accept routes such as 'appointments/1' and taking control or do I have to use a click event with a Backbone.history.navigate call like above?
You need to return false from your click .foo event handler, otherwise the browser will continue as if you'd clicked the link normally and request the actual /foo page from the server.
I think you've also got the call to Backbone.history.navigate("foo"); wrong - Backbone.history doesn't have a navigate function as far as I can see from the documentation. You should actually be calling .navigate on your Backbone.Router instance, and passing in the trigger option to cause it to call trigger the route. For example:
window.AppointmentApp.navigate("foo", { trigger : true } );
You may already know this but if you're planning on using pushState then you should really update your server side to support all the URLs that your client side does. Otherwise if a user decides to copy & paste the URL into another tab, they will just run into rails complaining that there is no route.
I am trying to get the ckeditor working. Obviously it doesn't make use of the textarea so on submit the form doesn't submit the text in the editor. Beceause I make use of polymorphic associations etc. I can't make a onsubmit function to get the value of the textarea (when the form is submitted) .
So I found this question: Using jQuery to grab the content from CKEditor's iframe
with some very good answers. The answers posted there keep the textarea up to date. That is very nice and just what I need! Unfortunately I can't get it to work.
Does somebody know why (for example) this doesn't work?
I have a textarea (rails but it just translates to a normal textarea):
<%= f.text_area :body, :id => 'ckeditor', :rows => 3 %>
And the following js:
if(CKEDITOR.instances.ckeditor ) {
CKEDITOR.remove(CKEDITOR.instances.ckeditor);
}
CKEDITOR.replace( 'ckeditor',
{
skin : 'kama',
toolbar :[['Styles', 'Format', '-', 'Bold', 'Italic', '-', 'NumberedList', 'BulletedList', 'Link']]});
CKEDITOR.instances["ckeditor"].on("instanceReady", function()
{
//set keyup event
this.document.on("keyup", CK_jQ);
//and paste event
this.document.on("paste", CK_jQ);
}
function CK_jQ()
{
CKEDITOR.instances.ckeditor.updateElement();
}
I get the following "error" in my firebug.
missing ) after argument list
[Break on this error] function CK_jQ()\n
Before submit do:
for(var instanceName in CKEDITOR.instances)
CKEDITOR.instances[instanceName].updateElement();
have you figured it out?
I'm using CKEditor version 3.6.1 with jQuery form submit handler. On submit the textarea is empty, which to me is not correct. However there is an easy workaround which you can use, presuming all your CKEditor textareas have the css class ckeditor.
$('textarea.ckeditor').each(function () {
var $textarea = $(this);
$textarea.val(CKEDITOR.instances[$textarea.attr('name')].getData());
});
Execute the above before you do your submit handling ie. form validation.
Thanks #JohnDel for the info, and i use onchange to make it update every change.
CKEDITOR.on('instanceReady', function(){
$.each( CKEDITOR.instances, function(instance) {
CKEDITOR.instances[instance].on("change", function(e) {
for ( instance in CKEDITOR.instances )
CKEDITOR.instances[instance].updateElement();
});
});
});
Combination of all of the above answers into one.
Create a new custom.js file and add this:
CKEDITOR.on('instanceReady', function(){
$.each( CKEDITOR.instances, function(instance) {
CKEDITOR.instances[instance].on("instanceReady", function() {
this.document.on("keyup", CK_jQ);
this.document.on("paste", CK_jQ);
this.document.on("keypress", CK_jQ);
this.document.on("blur", CK_jQ);
this.document.on("change", CK_jQ);
});
});
});
function CK_jQ() {
for ( var instance in CKEDITOR.instances ) { CKEDITOR.instances[instance].updateElement(); }
}
You don't have to worry about the name of the textarea, just add a class ckeditor in the textarea, the above and you are done.
ADD Function JavaScript for Update
function CKupdate() {
for (instance in CKEDITOR.instances)
CKEDITOR.instances[instance].updateElement();
}
It's work. Cool
Just Add
CKEDITOR.instances.textAreaClientId.on('blur', function(){CKEDITOR.instances. textAreaClientId.updateElement();});
where textAreaClientId is your instance name
Regards
CKEDITOR.instances["ckeditor"].on("instanceReady", function()
{
//set keyup event
this.document.on("keyup", CK_jQ);
//and paste event
this.document.on("paste", CK_jQ);
})
I just increase that to the response of T.J. and worked for me:
$("form").on("submit", function(e){
$('textarea.ckeditor').each(function () {
var $textarea = $(this);
$textarea.val(CKEDITOR.instances[$textarea.attr('name')].getData());
});
});
On load:
$(function () {
setTimeout(function () {
function CK_jQ(instance) {
return function () {
CKEDITOR.instances[instance].updateElement();
};
}
$.each(CKEDITOR.instances, function (instance) {
CKEDITOR.instances[instance].on("keyup", CK_jQ(instance));
CKEDITOR.instances[instance].on("paste", CK_jQ(instance));
CKEDITOR.instances[instance].on("keypress", CK_jQ(instance));
CKEDITOR.instances[instance].on("blur", CK_jQ(instance));
CKEDITOR.instances[instance].on("change", CK_jQ(instance));
});
}, 0 /* 0 => To run after all */);
});
There have been some API changes with the latest versions of CKEditor, so here's an answer for CKEditor 5:
let ckeditor;
// Create a CKEditor, and store its handle someplace that you may
// access later. In this example, we'll use the `ckeditor` variable:
ClassicEditor
.create(document.querySelector("textarea"), {})
.then(editor => { ckeditor = editor; });
// When your form submits, use the `updateSourceElement` method
// on the editor's handle:
document.querySelector("form").addEventListener("submit", function() {
ckeditor.updateSourceElement();
});
To my knowledge, CKEditor does this automatically when you submit a form, so this particular example shouldn't actually do anything. But it is useful when you need the content of the textarea to udpate without submitting the form that contains it.
All above answer are focusing on how to fix this error but I want to take the answer on what cause me this error
I had a
<textarea class="ckeditor" rows="6" name="Cms[description]"></textarea>
changed to
<textarea class="ckedit" rows="6" name="Cms[description]"></textarea>
I changed class attribute value to anything other than ckeditor and boom error gone.
Hope that help