Re-render partial after x-editable save - javascript

I use x-editable to allow the user to associate itself to another model. The styling changes based on what type of model the user is associated to.
Right now, it works, but the css class only changes after I refresh the page.
How would I go about resetting the css class, after x-editable saves the new value?
This is how my input looks like ->
== editable user, :heat_id, url: admin_user_path(user), type: "select", value: (user.heat.level if user.heat), source: Heat.all.map{ | heat | {value: heat.id, text: heat.level} }, class: "#{user.heat.badge if user.heat}"
I'd essentially need to reapply
class: "#{user.heat.badge if user.heat}"
Update
I figured out that x-editable-rails actually had this built in. The solution was to write ->
== editable user, :heat_id, url: admin_user_path(user), type: "select", value: (user.heat.level if user.heat), source: Heat.all.map{ | heat | {value: heat.id, text: heat.level} }, classes: Hash[Heat.all.map{ | heat | [heat.id, heat.badge]}], class: "#{user.heat.badge if user.heat}"
BUT, I still don't know how to change elements after a save using ajax.
For example, what I would like to do is, after a save event, to re-render the partial 'progress'.
How would I go about doing that?

$('.profile_editable').on('save', function(e, params) {
var progress_value = params.response.progress_value
$('.progress_title').text("Your profile is " + progress_value + "% completed" )
$('.bar').css('width', progress_value + '%');
});
Then, pass info in json response -->
def update
#common_app = CommonApp.find(params[:id])
if #common_app.update_attributes(common_app_params)
respond_to do |format|
format.html { render :action => "show" }
format.json { render json: {success: true, progress_value: #common_app.user.progress, user_name: #common_app.user.name } }
end
else
render json: {errors: #common_app.errors}, status: 400
end
end

Related

Won't save the attributes of a record

I'm trying to get the upgrade the example shown in this blog post
https://medium.com/#mitch_23203/the-exact-same-app-in-hyperstack-7f281cef46ca
to use hyperstack models like the followup blog post, but it just doesn't work.
Here is my code after I changed it:
class TodoIndex < HyperComponent
def create_new_todo_item
Todo.create(title: #todo)
#title = nil
end
render(DIV, class: 'ToDo') do
IMG(class: 'Logo', src: 'assets/logo.png', alt: 'Hyperstack Logo')
H1(class: 'ToDo-Header') { 'Hyperstack To Do' }
DIV(class: 'ToDo-Container') do
DIV(class: 'ToDo-Content') do
Todo.each do |item|
TodoItem(key: item, item: item.title)
.on(:delete_item) { item.destroy }
end
end
DIV do
INPUT(type: :text, value: #title)
.on(:change) { |e| mutate #title = e.target.value }
.on(:enter) { create_new_todo_item }
BUTTON(class: 'ToDo-Add') { '+' }
.on(:click) { create_new_todo_item }
end
end
end
end
Everything seems to work fine, and new Todo's are saved but the attributes are nil. Like the title doesn't get saved.
It should be:
def create_new_todo_item
Todo.create(title: #title) # not #todo
#title = nil
end
You set the title of Todo to its state value (#todo)...

Display Rails error messages inside a Bootstrap modal when using Selectize and Ajax

I'm trying to build an app that allows users to share quotes by artists about other artists. For instance, a quote by Bob Dylan about John Lennon. As such, my Artist model is set up in a way that allows an artist to be both the Speaker and Topic on a Quote, and each Quote belongs_to each Artist as the Speaker or Topic.
I'm having trouble getting a Rails error message to display inside a Bootstrap modal when using Selectize to trigger the modal. I got the modal working by following this demo.
The modal is used to create a new Artist from the quotes/new form, but I can't get the error messages for the Artist model to display in the Bootstrap modal or on the quotes/new page. When I try to create something that triggers an error message (such as validates_uniqueness) in the modal, it just closes the modal and doesn't display the error message. Everything else is working as expected.
What am I missing to connect the Ajax request to the view?
Here's the relevant section of my form:
<%= f.label :speaker, 'Who said it?' %>
<%= f.collection_select :speaker_id, #speakers, :id, :name,
{prompt: 'Select an artist'}, {class: 'form-control selectize-speaker'} %>
Full source for quotes/form.html.erb
Here's the relevant code in my controller:
class ArtistsController < ApplicationController
def create
#artist = current_user.artists.build(artist_params)
authorize #artist
respond_to do |format|
if #artist.save
if request.referer.include?("artists")
flash[:success] = "Artist was successfully created."
format.html { redirect_to #artist }
else
format.json { render json: #artist }
end
else
format.html { render :new }
format.json { render json: #artist.errors.full_messages }
end
end
end
end
Full source for artists_controller.rb
Relevant javascript code:
$(document).on('turbolinks:load', function() {
var selectizeCallback = null;
// Selectize Speaker
$('.speaker-modal').on('hide.bs.modal', function(e) {
if (selectizeCallback != null) {
selectizeCallback();
selecitzeCallback = null;
}
$('#new_speaker').trigger('reset');
});
$('#new_speaker').on('submit', function(e) {
e.preventDefault();
$.ajax({
method: 'POST',
url: $(this).attr('action'),
data: $(this).serialize(),
success: function(response) {
selectizeCallback({value: response.id, text: response.name});
selectizeCallback = null;
$('.speaker-modal').modal('toggle');
}
});
});
$('.selectize-speaker').selectize({
create: function(input, callback) {
selectizeCallback = callback;
$('.speaker-modal').modal();
$('#speaker_name').val(input);
}
}); // end selectize speaker
}); // end document on
Full source for quotes.js.
And my error message partial, shared/_error_messages.html.erb:
<% if object.errors.any? %>
<div id='error_explanation'>
<div class='alert alert-danger'>
<button type='button' class='close' data-dismiss='alert'>×</button>
<p><strong>The form contains
<%= pluralize(object.errors.count, 'error') %>.</strong></p>
<ul>
<% object.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
</div>
<% end %>
Additional source files:
models/quote.rb
models/artist.rb
controllers/quotes_controller.rb
Both a successful and unsuccessful save are returning a 200 response, which means that your success callback will be called:
success: function(response) {
selectizeCallback({value: response.id, text: response.name});
selectizeCallback = null;
$('.speaker-modal').modal('toggle');
}
This always toggles the modal, therefore closing it.
If you ensure that the response is a 4xx on validation error, then you can define an error callback which populates your errors list and does not close the modal.
So instead of:
format.json { render json: #artist.errors.full_messages }
Use something like:
format.json { render json: #artist.errors.full_messages, status: :bad_request }
Then, pass an error callback to your AJAX call:
error: function(response) {
// somehow populate your errors list
// display the errors list
}
This won't work right now, though, because the errors container won't exist: you only render it under this condition:
object.errors.any?
Which, on initial load, will always evaluate false. What you can instead do is always render the errors container, default it to some hidden class if there aren't any errors, and in your error callback, remove the hidden class after it's populated.

Cant execute coffeescript in modal

first of all, im still learning Ruby on rails, currently im working on rails 4.2.6.
I have a problem with my code, i have a modal where i want to show the information dynamically with ajax (Calling a method in a controller and showing the information on the modal without closing it) but i have a problem, i cant call any function on the modal.
.col-xs-7
%h5="#{period.name}"
.col-xs-5
%form
.input-group
%input.form-control{type: "text", placeholder: "#{t('reports.periods')}"}/
.input-group-btn
%button.btn.transparent-button.dropdown-toggle{"data-toggle" => |
"dropdown", |
type: "button"} |
= svg_icon('icon-arrow-down')
%ul.dropdown-menu.pull-right
- #batch_id.periods.each do |period|
%li
= link_to period.name, '#', :onclick => "myFunction", id: "#{period.id}_id", value: period.id
.row.actions-container
.col-xs-12
%h4="#{#student_id.name}"
%hr
.row.actions-container
.col-xs-12
%form
= label_tag t('batches.observations')
%br
= text_area_tag 'rejection_comments', #comment.try(:comment) , class: 'form-control', :rows => 10, :cols => 30
- content_for(:page_javascript) do
:coffeescript
myFunction = ->
alert 'hello world'
return
Right now im trying only to call the function 'MyFunction' after i select a period but it throws an error:
myFunction is not defined
But if i do this:
- #batch_id.periods.each do |period|
%li
= link_to period.name, '#', :onclick => "alert('hello')", id: "#{period.id}_id", value: period.id
It works...
Can someone tell me what im doing wrong? I want to do the ajax thing as soon as possible.
Ps: The comment part on the text area is the info i want to get from the controller dynamically.
Thanks!

Completing items in ruby on rails 4

I have migrated a :completed boolean, I then added it to my form like so (simple_form)
<%= f.input :completed, as: :boolean %>
This allows me to update completed, not completed in the edit view.
How can I edit the :completed method in my index view? I want to be able to update complete or not complete on the fly.
EDIT:
My Form
<%= f.input :completed, as: :boolean, input_html: { class: 'completed', id: #todo.id } %>
My View (label has to be after input as per materializecss)
<%= check_box_tag todo.id, 'completed', todo.completed?, class: 'completed' %>
<label class="strikethrough">
COMPLETE
</label>
The JS
// This could be other events as well, so add/change/remove the event trigger as needed
$(document).on('click', '.completed', function(){
updateCompleted($(this));
});
function updateCompleted($el) {
var id = $el.attr('id'),
val = $el.is(':checked');
$.PATCH({
url: '/todos/'+id,
data: { todo: { completed: val } },
success: function(){ whatever },
error: function() { whatever }
});
}
My Controller
params.require(:todo).permit(:title, :item, :image, :completed)
You are going to require some AJAX here. In my experience, doing this is a bit outside of the "rails way", but totally possible.
First, make sure you have the ID of the object somewhere in the dom:
<%= f.input :completed, as: :boolean, input_html: { class: 'completed', id: myobject.id %>
I used the simple_form syntax since that's what it appears you are using for your form builder. If not, comment back and I'll adjust the tag.
Secondly, add a jquery event listener:
// This could be other events as well, so add/change/remove the event trigger as needed
$(document).on('click', '.completed', function(){
updateCompleted($(this));
});
function updateCompleted($el) {
var id = $el.attr('id'),
val = $el.is(':checked');
$.PATCH({
url: '/your_endpoint/'+id,
data: { your_object_name: { completed: val } },
success: function(){ whatever },
error: function() { whatever }
});
}
And in your controller:
private
def your_object_params
params.require(:your_object).permit(..., :completed)
end
That's basically it.
Basically you will want to make a post to the update action from the index action. I would use JavaScript but you can also use a hard refresh if you want to stick with rails. Here is a good intro if you are not familiar with using JS in your rails app. http://railscasts.com/episodes/324-passing-data-to-javascript.

Autocomplete with typeahead in rails 3

I'm developing autocomplete for a particular form in my rails app; for this purpose I'm using typeahead.js with custom controller method. So far, it works but I need using those values within the form again so that I can press the submit button and the form will be posted and processed by rails normally. How can I do this? Here's the code right now
.page-header
%h1
= #org.name
%small= t('.title')
= form_for #org_admin, |
url: organization_organization_admins_path(#organization) do |f|
.form-group
= f.label t('.user')
= f.hidden_field :user, id: 'user_id'
%input.typeahead{ :type => "text", :autocomplete => "off"}
= f.submit t('.submit'), class: 'btn btn-primary'
= link_to t('.back'), organization_organization_admins_path(#organization)
:javascript
$(document).ready(function() {
$('input.typeahead').typeahead({
name: 'names',
remote: "#{search_organization_organization_admins_path(#organization)}?term=%QUERY",
engine: Hogan,
template: '<p><strong>{{username}}</strong></p>',
limit: 10
}).on('typeahead:selected', function(e, data){
$('#user_id').value = data.id
});
});
So, I would like to populate the :user attribute in the form with the json object returned by the controller
Nevermind, I figured out... the above code is in the right path, except for the call to this line
$('#user_id').value = data.id
Since I'm using jQuery to select the hidden element I had to use the jQuery val function instead
$('#user_id').val(data.id)

Categories