Rails + Backbone - Backbone routes not working - ruby-on-rails

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

Related

jQuery Ajax Form Submit Fails

I am developing an MVC4 mobile app that uses several forms which are loaded into a section on the layout via ajax. I've got jQuery mobile set with Ajax turned off so I can manage the Ajax myself. Most of the forms work fine, the load and submit via ajax as they should. However, so far there is one form that refuses to fire the form submit and submit the form via ajax like the rest. First, the form is loaded when a user clicks to add a contact and this works fine:
// Handle the add contact button click
$('#btnAddNewContact').on('click', function (e) {
e.preventDefault();
// Make sure a location was selected first.
var locationID = $('#cboLocation').val();
if (locationID.length === 0) {
//$('#alertTitle').text('REQUIRED');
$('#alertMsg').html("<p>A Contact must be associated with a Location.</p><p>Please select or add a Location first.</p>");
$('#alertDialogDisplay').click();
} else {
SaveOpportunityFormState();
$.cookie('cmdLocationId', locationID, { path: '/' });
$.mobile.loading('show');
$.ajax({
url: '/Contact/Add',
type: 'GET',
cache: false,
success: function (response, status, XMLHttpRequest) {
$('section.ui-content-Override').html(response);
// Refresh the page to apply jQuery Mobile styles.
$('section.ui-content-Override').trigger('create');
// Force client side validation.
$.validator.unobtrusive.parse($('section.ui-content-Override'));
},
complete: function () {
$.cookie('cmdPreviousPage', '/Opportunity/Add', { path: '/' });
AddContactLoad();
ShowSearchHeader(false);
$.mobile.loading('hide');
},
error: function (xhr, status, error) {
// TODO - See if we need to handle errors here.
}
});
}
return false;
});
Notice that after successfully loading the form the AddContactLoad() function is fired. This works fine and here is that code:
function AddContactLoad() {
$('#contactVM_Phone').mask('(999) 999-9999? x99999');
$('#frmAddContact').on('submit', function (e) {
e.preventDefault();
if ($(this).valid()) {
$.mobile.loading('show');
$.ajax({
url: '/Contact/Add',
type: 'POST',
cache: false,
data: $(this).serialize(),
success: function (response, status, XMLHttpRequest) {
if (!response) { // Success
ReturnToAddOpportunity();
} else { // Invalid Form
$('section.ui-content-Override').html(response);
// Force jQuery Mobile to apply styles.
$('section.ui-content-Override').trigger('create');
// Force client side validation.
$.validator.unobtrusive.parse($('section.ui-content-Override'));
AddContactLoad();
$.mobile.loading('hide');
}
},
complete: function () {
},
error: function (xhr, status, error) {
// TODO - See if we need to handle errors here.
}
});
}
return false;
});
$('#btnCancel').on('click', function (e) {
e.preventDefault();
// See where add contact was called from.
var previousPage = $.cookie('cmdPreviousPage');
if (previousPage.indexOf("Detail") >= 0) {
ReturnToOpportunityDetails();
} else {
ReturnToAddOpportunity();
}
return false;
});
}
If I click the cancel button, that code is fired so I know this is working too. Here is my form code:
#using (Html.BeginForm("Add", "Contact", FormMethod.Post, new { #id = "frmAddContact" }))
{
#Html.ValidationSummary(true)
#Html.AntiForgeryToken()
-- Form Fields Here --
<div class="savecancel" >
<input type="submit" value="Save" data-mini="true", data-theme="b", data-inline="true" />
Cancel
</div>
}
As you can see the form is named frmAddContact and that is what the AddContactLoad() function is attaching the submit event to. To save my sole I cannot figure out why the form does not submit via the ajax post like every other form in the app. Am I missing some kind of initialization, I just don't know. If anyone can please help I'd really appreciate it!!
As it turns out, I had created a custom unobtrusive Ajax validator for a phone number then copied and pasted it to do the same with a zip code. Unfortunately in the process I forgot to rename a variable and thus an error was occurring in the validation script which caused the problem. In the mean time, if you're reading this, you might take a note of the code here and how to inject HTML into a page via Ajax and jQuery mobile. I've never found this in a book or on the web and it contains some very useful methodology and syntax. On the form submit the reason I'm checking for the empty response is I just return null from the controller to validate the form was valid and the save worked in which case I send them to a different HTML injection i.e. that page they originally came from. If null is not returned I inject that page with the HTML containing the original form and error markup so the user can make corrections then resubmit. I'm also calling a form load method that attaches handlers to the HTML once it's injected into the main page. Hope this helps somebody!

changepage after loadpage with variable posted

I would like to fire a changepage after a loadpage.
Below is the code I use.
After a submit, a database action is fired at an external site (with loadPage). That works.
Next I would like to change to another page with the guid (unique ID) variable posted.
I can't get this working.
Hope somebody can. Thanks in advance.
$(document).on('pageinit', '#page1', function(){
$('form').submit(function(){
var guid = GUID();
$.mobile.loadPage( "http://domain.com/dbaction.php?guid="+guid, {
type: "post",
data: $("form#addtegel").serialize()
});
return false;
$.mobile.changePage ($("#page2"),{ transition: "slideup"} );
});
});
$(document).on('pageinit', '#page2', function(){
DoSomething(guid);
});
First, you need to make guid a global variable. At the moment, it's local to your form submission, so it cannot be accesses outside that form submit action.
Second, instead of using loadPage() - which is jQuery Mobile's internal function called by changePage() by the way - use $.ajax() like this:
var guid;
$(document).on('pageinit', '#page1', function(){
$('form').submit(function(){
window.guid = GUID();
$.ajax({
url: "http://domain.com/dbaction.php?guid="+guid,
type: "post",
data: $("form#addtegel").serialize(),
success: function() {
$.mobile.changePage ($("#page2"), { transition: "slideup"} );
}
});
return false;
});
});
$(document).on('pageinit', '#page2', function(){
DoSomething(window.guid);
});
Also, please be aware that mixing GET and POST data is a very bad habit. I'm talking about this url: "http://domain.com/dbaction.php?guid="+guid
There should only be GET or POST data present in a single request, not both. Would it not be possible to pass guid to dbaction.php in the POST (using a hidden field in your form)?

Html imput type="image" onclick event

Friends I have a problem
We need to make a user control that has the ability to delete itself, I made it but we did not clear the mechanism for removal, it should be tied to a nice picture. Code that is attached to the frame is given below, but not
$('#delete').bind('click', function () {
alert('test');
var urlA = '<%=Url.Action("DeleteMessage","Ticket")%>';
$.ajax({
url: urlA,
type: 'POST',
data: { idMessage:$(this).parents("div:first").find("input[name='MessageID']").val(),idticket:$('#TicketID').val() },
success: function (data) {
alert(data);
}
});
});
But when I write this, but to throw me to the homepage what's wrong
$('#delete').live('click', function ()
$("#delete").live("click", function(){
//code
$(this).remove(); //delete itself
});
If your image is declared as input type="image" then it will behave like a submit button and submit your page. You should prevent the default behavior of submitting the page by adding an event.preventDefault() or equivalent to your javascript function.

Backbone.js routes are not being triggered

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.

Ckeditor update textarea

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

Resources