I am trying to customize Spree_i18n frontend nav-bar locale and am having some issues changing it from a select_tag to a link_to. I am trying to make it appear with only two locales selections EN/CN. What would the best solution for this be?
locale.js
load = function() {
return $('#locale-select select').change(function() {
return $.ajax({
type: 'POST',
url: $(this).data('href'),
data: {
locale: $(this).val()
}
}).done(function() {
return window.location.reload();
});
});
};
navbar.html.erb
<li id="locale-select" data-hook>
<%= form_tag set_locale_path, class: 'navbar-form' do %>
<div class="form-group">
<label for="locale" class="sr-only"><%= t(:'i18n.language') %></label>
<%= select_tag(:locale, options_for_select(supported_locales_options, I18n.locale), class: 'form-control', data: { href: set_locale_path }) %>
<noscript><%= submit_tag %></noscript>
</div>
<% end %>
</li>
My custom variant
<%= link_to 'en', spree.set_locale_path(switch_to_locale: :en), method: :post %>
Related
I am starting a new Rails 7 app and recently found out that we can't use ujs anymore :( I found a plugin called mrujs which is working correctly to send my forms remotely to the server. I am also using stimulus to handle various javascript functions on the page.
The issue that I'm having is my response back after ajax:success processes is not iterable:
TypeError: object is not iterable (cannot read property Symbol(Symbol.iterator))
Below is my HTML, Rails, and Stimulus Code:
HTML
<%= form_with model: Article.new, html: { data: { remote: true, type: "html", "action": "ajax:success->modal-forms#onPostSuccess ajax:error->modal-forms#onPostError" } } do |f| %>
<%= f.label :title, "Article Title" %>
<%= f.text_field :title, class: "form-control" %>
<%= f.submit "Save Article", class: "btn btn-primary" %>
<% end %>
Ruby / Rails
def create
#article = Article.create(article_params)
if #article.errors.any?
render partial: 'error', article: #article, status: :bad_request
else
render #article
end
end
This returns a basic html page that would be inserted into another location within the page.
<li><%= #article.title %></li>
Stimulus Action
onPostSuccess(event) {
event.preventDefault()
const [data, status, xhr] = event.detail
// This is where I get the issue of 'Not Iterable'
}
event.detail gives me the not iterable error. Does anyone know how I can get my response from rails to be formatted so the [data, status, xhr] section will actually work?
If hotwire or turbo is needed for this an example would be extremely helpful :)
Thanks
Eric
This may not be the correct way but it does work:
html
<div data-container="remote">
<%= form_with model: Person.new, html: { data: { "action": "submit->remote#submit" } } do |f| %>
<%= f.text_field :first_name %>
<%= f.submit :submit %>
<% end %>
</div>
peole rails controller
def create
#person = Person.new(person_params)
if #person.save
render json: #person
else
render partial: 'people/person', locals: { person: #person }, status: :unprocessable_entity
end
end
remote stimulus controller
submit(event) {
event.preventDefault()
fetch(event.target.action, {
method: 'POST',
body: new FormData(event.target),
}).then(response => {
console.log(response);
if(response.ok) {
return response.json()
}
return Promise.reject(response)
}).then(data => {
console.log(data)
}).catch( error => {
console.warn(error)
});
}
I am trying to add google autocomple api, but it works only after page reload and sometimes doesn't works even after ``page reload , Below is the code:
<%= javascript_include_tag 'https://maps.googleapis.com/maps/api/js?key=' + Rails.application.secrets.google_api_key + '&libraries=places' %>
<div class="mui-textfield" data-turbolinks="false">
<input type="hidden" name="id" value='' id="user_id">
<%= text_field_tag :location, nil, id: 'txtPlaces', class: "form-text", placeholder: '', required: true %>
<%= hidden_field_tag :full_address, nil, id: 'full_address', class: "form-text", placeholder: '' %>
</div>
<script>
var ready = function () {
var options = {
type:['(regions)'],
componentRestrictions: {
country: ['au']
}
};
google.maps.event.addDomListener(window, 'load', function () {
var input = document.getElementById('txtPlaces');
var places = new google.maps.places.Autocomplete(input, options);
google.maps.event.addListener(places, 'place_changed', function () {
$("#full_address").val($("#txtPlaces").val());
});
});
// This is some custom requirement
$('.save-address').on('click', function(e){
if($("#full_address").val() !== $("#txtPlaces").val()){
e.preventDefault();
e.stopPropagation();
$("#txtPlaces").val('');
$(this).submit();
}
});
};
<%#*$(document).ready(ready);%>
<%#*$(document).on('page:load', ready);%>
$(document).on("turbolinks:load", ready);
</script>
I have tried both above ready and page:load function as well but no luck
Other than this, below is the code to reach above page
<li><%= link_to('Active', admin_staffs_path(status: 'accepted'), data: { turbolinks: false })
I have a dropdown box to chose the number of tickets that one wants to buy. I want to update the fields after it to reflect the value once it is clicked. Here is a snippet of my form currently:
<%= form_for :transaction, :url => new_transaction_path(:event_id => #event.id), :method => 'GET' do |f| %>
<table style="width:100%">
<tr style="border-bottom: 1px solid #999999">
<td><h4>Number of Guests</h4></td>
<td>
<%= f.select(:quantity, (1..20))%>
</td>
</tr>
<tr style="border-bottom: 1px solid #999999">
<!-- replace (1) with the value from the f.select dropdown -->
<td><h4><%= #original_event_price %> x (1) guest(s)</h4></td>
</tr>
</table>
<%= f.submit 'Request to Book', class: 'button mt1 btn-request-to-book' %>
<% end %>
I want to replace (1) with the value from the f.select dropdown in the last table row to the value of guests that the user chooses.
EDIT WITH WORKING SOLUTION
<%= form_for :transaction, :url => new_transaction_path(:event_id => #event.id), :method => 'GET' do |f| %>
<table style="width:100%">
<tr style="border-bottom: 1px solid #999999">
<td><h4>Number of Guests</h4></td>
<td>
<%= f.select :quantity, (1..20), {}, { :onChange=>'mytest()', :id=>'quantitySelect' } %>
</td>
</tr>
<tr style="border-bottom: 1px solid #999999">
<!-- replace (1) with the value from the f.select dropdown -->
<td><h4><%= #original_event_price %> x (1) guest(s)</h4></td>
</tr>
</table>
<%= f.submit 'Request to Book', class: 'button mt1 btn-request-to-book' %>
<% end %>
SCRIPT
<script type="text/javascript">
function mytest() {
var quantity = $('#quantitySelect').val();
$('#quantityRow').html("<h4><%= #original_event_price %> x (" + quantity + ") guest(s)");
}
</script>
Problem : How to load value in other field based on drop-down selection
Solution:
<div class="field form-group">
<%= form.label :grade %>
<%= form.select(:grade, options_for_select(['A', 'B', 'C', 'D', 'E', 'F']), {:include_blank => 'Select Grade'}, class:"form-control", placeholder:"Grade", onchange: "loadRemarksBasedOnGrade()") %>
</div>
<div class="field form-group">
<%= form.label :remarks %>
<%= form.text_field :remarks, class:"form-control", placeholder:"Remarks", readonly: true %>
</div>
JavaScript :
<script type="text/javascript">
function loadRemarksBasedOnGrade() {
var grades = [];
grades['A'] = "Excellent";
grades['B'] = "Very Good";
grades['C'] = "Good";
grades['D'] = "Average";
grades['E'] = "Below average";
grades['F'] = "Failed";
let grade = document.getElementById("student_grade");
if(grades[grade.value] !== undefined) {
document.getElementById("student_remarks").value = grades[grade.value];
} else {
document.getElementById("student_remarks").value = "";
}
}
</script>
Note: So onchnage event loadRemarksBasedOnGrade update value based on id.
You can do this with jQuery:
Let's add an id: "quantitySelect" on the quantity field
Let's also add an id: "quantityRow" on the td field
$(function(){
$('.quantitySelect').change(function(e){
e.preventDefault();
var quantity = $('.quantitySelect').val();
$('.quantityRow').html("<h4><%= #original_event_price %> x (" + quantity + ") guest(s)");
});
});
You can also add if checks to see if the quantity is > 1 and append the word guest to guests.
Below is my code in full for both the application controller and the application.html.erb, I really can't work this out, what is wrong?! this accepts standard values in the high chart, for example, just straight numbers but once I try to call values stored in the array it rejects it. I don't know why. Thanks
class ApplicationController < ActionController::Base
require 'nokogiri'
require 'open-uri'
protect_from_forgery
before_filter :set_locale
def index
#doc= Nokogiri::XML(open("http://api.worldbank.org/countries/BRA/indicators/1.0.HCount.2.5usd?per_page=10&date=1960:2014"))
m = #doc.xpath("//wb:value").collect(&:text)
#values = Array.new
m.each do |m|
#values << m
end
end
end
complete application.html.erb code below:
<!DOCTYPE html>
<html>
<head>
<title>Project</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= javascript_include_tag :defaults %>
<%= csrf_meta_tags %>
<script src="http://code.highcharts.com/highcharts.js"></script>
<script src="http://code.highcharts.com/modules/exporting.js"></script>
<script>
$(function () {
$('#container').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Brazil Poverty Headcount'
},
subtitle: {
text: 'Source: WorldBank.com'
},
xAxis: {
categories: [
'2009',
'2008',
'2007',
'2006',
'2005',
'2004',
'2003',
'2002',
'2001',
]
},
yAxis: {
min: 0,
title: {
text: 'X-Axis Data'
}
},
tooltip: {
headerFormat: '<span style="font-size:10px">{point.key}</span><table>',
pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' +
'<td style="padding:0"><b>{point.y:.1f} mm</b></td></tr>',
footerFormat: '</table>',
shared: true,
useHTML: true
},
plotOptions: {
column: {
pointPadding: 0.2,
borderWidth: 0
}
},
series: [{
name: 'Brazil',
data: <%=#values.inspect%>
}]
});
});
</script>
</head>
<body>
<div style= "margin:50px">
<div id="container" style="min-width: 310px; height: 600px; margin: 15 auto"></div>
<div id ="signing" style="width:200px; height:200px; float:right;">
<% if current_user %>
Logged in as <%= current_user.email %>
<%= link_to "Log Out", logout_path %>
<% else %>
<%= link_to "Sign Up", signup_path %>
<%= link_to "Log In", login_path %>
<% end %>
</div>
<div id="admin" style="width:100px; height:100px; float:right;">
<%= link_to "Admin", new_admin_user_session_path %>
</div>
<div>
Language:
<%= link_to_unless_current "English", locale: "en" %> |
<%= link_to_unless_current "Spanish", locale: "sp" %>
</div>
<%= yield %>
</div>
</body>
</html>
I have actually deployed your app and try the following.
Create controller chart:
rails g controller chart
Edit app/controllers/chart_controller.rb and add the following:
def index
#doc = Nokogiri::XML(open("http://api.worldbank.org/countries/BRA/indicators/1.0.HCount.2.5usd?per_page=10&date=1960:2014"))
m = #doc.xpath("//wb:value").collect(&:text)
#values = Array.new
m.each do |m|
#values << m.to_f
end
end
Now create file views/chart/index.html.erb and paste following:
<!DOCTYPE html>
<html>
<head>
<title>Maxo</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= javascript_include_tag "http://code.highcharts.com/highcharts.js" %>
<%= javascript_include_tag"http://code.highcharts.com/modules/exporting.js" %>
<%= csrf_meta_tags %>
<script>
$(function () {
$('#container').highcharts({
chart: {
type: 'column'
},
title: {
text: 'Brazil Poverty Headcount'
},
subtitle: {
text: 'Source: WorldBank.com'
},
xAxis: {
categories: [
'2009',
'2008',
'2007',
'2006',
'2005',
'2004',
'2003',
'2002',
'2001',
]
},
yAxis: {
min: 0,
title: {
text: 'X-Axis Data'
}
},
tooltip: {
headerFormat: '<span style="font-size:10px">{point.key}</span><table>',
pointFormat: '<tr><td style="color:{series.color};padding:0">{series.name}: </td>' +
'<td style="padding:0"><b>{point.y:.1f} mm</b></td></tr>',
footerFormat: '</table>',
shared: true,
useHTML: true
},
plotOptions: {
column: {
pointPadding: 0.2,
borderWidth: 0
}
},
series: [{
name: 'Brazil',
data: <%= #values.inspect %>
}]
});
});
</script>
</head>
<body>
<div style= "margin:50px">
<div id="container" style="min-width: 310px; height: 600px; margin: 15 auto"></div>
</div>
<%= yield %>
</div>
</body>
</html>
Also make sure that you have proper routing rule added to: config/routes.rb. For just simplicity you could just add:
root :to => 'chart#index'
In that case when you localhost:3000, you will get the chart/index view automatically. I have tested it and it works fine.
Just for any case views/layouts/application.html.erb should look:
<!DOCTYPE html>
<html>
<head>
<title>Test2</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
<%= yield %>
</body>
</html>
I've ran into some trouble trying to get partial updates to work in ASP.NET MVC2. (I think) I followed the tutorials I found online pretty closely, but the Ajax part isn't working. The controller does what it's supposed to do without errors, but the page doesn't update itself. When I refresh the page I can see the result of my action though.
Here is the code for the user control that's supposed to update itself:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Ideas.Models.Comment>" %> <script src="../../Scripts/jquery-1.4.1.js" type="text/javascript"></script> <script src="../../Scripts/MicrosoftAjax.js" type="text/javascript"></script> <script src="../../Scripts/MicrosoftMvcAjax.js" type="text/javascript"></script> <script type="text/javascript">
function AnimateVotebox() {
$("#commentbox").animate({ fontSize: "1.5em" }, 400);
}
</script> <div id="commentbox">
<div class="display-label">
<i><%: Html.ActionLink(Model.User1.UserName, "Details", "User", new { id = Model.User1.LoweredUserName.Replace(' ', '-') }, null)%> zegt:</i>
</div>
<div class="display-label"><%:Model.text %></div>
<% bool canPost = Ideas.Helpers.UserHelper.CanPost(HttpContext.Current); %>
<% if (Model.CommentVotes.Count != 0) %>
<% { %>
<div class="display-label"><%= Html.Encode(Model.UpVotes)%> van de
<%= Html.Encode(Model.Votes)%> gaan akkoord.</div>
<% if (canPost)
{ %>
<% if (Model.HasVoted((Guid)Membership.GetUser(Context.User.Identity.Name).ProviderUserKey) < 0) %>
<% { %>Stem:
<%= Ajax.ActionLink("-", "VoteComment", "Votes",
new { id = Model.id, up = false },
new AjaxOptions { UpdateTargetId = "commentbox", OnSuccess = "AnimateVotebox" }, null)%>
<%= Ajax.ActionLink("+", "VoteComment", "Votes",
new { id = Model.id, up = true },
new AjaxOptions { UpdateTargetId = "commentbox", OnSuccess = "AnimateVotebox" }, null)%>
<% } %>
<% else %>
<% { %>Wijzig stem:
<% if (Model.HasVoted((Guid)Membership.GetUser(Context.User.Identity.Name).ProviderUserKey)
== 0) %>
<% { %>
<%= Ajax.ActionLink("-", "ChangeCommentVote", "Votes",
new { id = Model.id, up = false },
new AjaxOptions { UpdateTargetId = "commentbox", OnSuccess = "AnimateVotebox" }, null)%>
<p style="color:gray; font-size:20;"">+</p>
<% } %>
<% else %>
<% { %>
<p style="color:gray; font-size:20;"">-</p>
<%= Ajax.ActionLink("+", "ChangeCommentVote", "Votes",
new { id = Model.id, up = true },
new AjaxOptions { UpdateTargetId = "commentbox", OnSuccess = "AnimateVotebox" }, null)%>
<% } %>
<% } %>
<% } %>
<br />
<% } %>
<% else %>
<% { %>
<div class="display-label">Nog geen stemmen</div><br />
<% if (canPost)
{ %>
Stem: <%= Ajax.ActionLink("-", "VoteComment", "Votes",
new { id = Model.id, up = false },
new AjaxOptions { UpdateTargetId = "commentbox", OnSuccess = "AnimateVotebox" }, null)%>
<%= Ajax.ActionLink("+", "VoteComment", "Votes",
new { id = Model.id, up = true },
new AjaxOptions { UpdateTargetId = "commentbox", OnSuccess = "AnimateVotebox" }, null)%>
<% } %>
<% } %>
<% if (HttpContext.Current.User.IsInRole("Moderator") || HttpContext.Current.User.IsInRole("Administrator"))%>
<% { %>
<%: Html.ActionLink("Geef probatie...", "ProbateUser", "Mod", new { comment = Model.id }, null) %>
<%: Html.ActionLink("Verwijder...", "BanUser", "Mod", new { comment = Model.id }, null) %>
<% } %>
</div>
Note that if I don't use jQuery the problem occurs as well.
And here's the controller:
[UserAuthorize]
[Authorize]
public ActionResult VoteComment(int id, bool up)
{
Comment comment = crep.GetComment(id);
CommentVote vote = new CommentVote();
vote.isup = up;
vote.user = (Guid)Membership.GetUser(User.Identity.Name).ProviderUserKey;
comment.CommentVotes.Add(vote);
crep.Save();
return PartialView("CommentUserControl", crep.GetComment(id));
}
[UserAuthorize]
[Authorize]
public ActionResult ChangeCommentVote(int id, bool up)
{
Comment comment = crep.GetComment(id);
CommentVote vote = comment.CommentVotes
.Where(v => v.user == (Guid)Membership.GetUser(User.Identity.Name).ProviderUserKey
&& v.comment == id).SingleOrDefault();
vote.isup = up;
crep.Save();
return PartialView("CommentUserControl", crep.GetComment(id));
}
Don't know if this matters, but the usercontrol is loaded inside a view that's linked to a different controller than the one above. The ActionLinks work fine though and trigger actions on the VotesController.
I don't see your ajax call, but from the little snippet under your first code block I assume you are using jQuery. I was seeing problems with IE showing changes from an ajax callback until I added the "cache: false" flag. I guess if this isn't the problem, does it happen in all browsers? Maybe show your ajax call also.
To call partial update and invoke controller action i use jQuery like this
$.getJSON(urlModeli, null, function (data) {
/*Do something with the data*/
}
and update the content afterwards.
And i did have a problem with IE showing the new content, cause i had cache:true on tabs that contained the data i was updating so browser just cached the old value and didn't show the new one, except on refresh