Change part of link with jquery - javascript

I am using Ransack for sorting. I couldn't find way to change sorting links when search and sorting uses just ajax. So I am developing my own solution to change link and some other stuff.
So far I have this
Ruby
<%= search_form_for #search, :class=>"search",:id=>"search-menio",:remote=>"true", url: advertisements_path, :method => :get do |f| %>
<div class="sort-link-css">
<%= sort_link(#search, :price,"CENA", {},{ :remote => true, :method => :get }) %>
</div>
<%end%>
that generates this :
<div class="sort-link-css">
<a class="sort_link asc" data-method="get" data-remote="true" href="/lv/advertisements?q%5Bs%5D=price+desc">CENA ▲</a>
</div>
My goal:
When user clicks on this link it will change link class that represents sorting order and end of the link that also represents sorting order.
asc -> desc
desc -> asc
And then it submits search form.
Problem:
For first click I see some blinking and changes, but when I try second click nothing happens.
My script:
$('.sort-link-css > a').click(function() {
var className = $(this).attr('class');
if (className = "sort link asc") {
$(this).removeClass('sort link asc');
this.href = this.href.replace('desc', 'asc');
$(this).attr('class', 'sort link desc');
} else if (className = "sort link desc") {
$(this).removeClass('sort link desc');
this.href = this.href.replace('asc', 'desc');
$(this).attr('class', 'sort link asc');
}
$('.search').submit();
})
What I am doing wrong ?

Ideally you would use jQuery.hasClass or jQuery.is to determine if an element has the specified class or classes.
You also need to update the display before navigation or form submit. You can do all this:
$('.sort-link-css > a').click(function(e) {
// cancel the click event on the link
e.preventDefault();
var $this = $(this);
if ($this.is('.asc')) {
this.href = this.href.replace('desc', 'asc');
} else if ($this.is('.desc')) {
this.href = this.href.replace('asc', 'desc');
}
$this.toggleClass('asc desc');
setTimeout(function() {
// I am not sure if you want to load the link href
// or submit the form; use one of the following
window.location = $this.get(0).href;
$('.search').submit();
}, 100);
});

Please try using hasClass().
https://api.jquery.com/hasclass/
$(this).hasClass( "sort link asc" )

Ok there are quite a few mistakes in your jQuery. You class="sort_link asc" are in fact two classes and not three. I have made a fiddle, just try to understand it and you will see where you are going wrong: FIDDLE
$('.sort-link-css > a').click(function () {
var className = $(this).attr('class');
console.log(className);
if (className == "sort_link asc") {
$(this).removeClass('sort_link asc');
alert("removed class sort_link asc");
} else if (className == "sort_link desc") {
$(this).removeClass('sort link desc');
this.href = this.href.replace('asc', 'desc');
$(this).attr('class', 'sort link asc');
}
else {
alert("all tests failed");
}
})

Related

jQuery + Rails: How to get id of button user clicked

I have spent hours trying to resolve this problem and reviewing other similar StackOverflow questions (1) (2), but none seem to have an answer to my problem..
I can't get past this error: ReferenceError: id is not defined. Alert does not show too.
$("button.btn-tag-cat").click(function(e){
e.preventDefault();
var id = $(this).prop('id');
alert(id);
id.find('span').show();
}, function(){
id.find('span').hide();
});
I have tried the following ways to using the id variable but none work.
$(id).find('span').show();
$("#" + id).find('span').show();
However, when i remove the chunk of code below the alert, the alert pops up with the correct id belonging to the button.
$("button.btn-tag-cat").click(function(e){
e.preventDefault();
var id = $(this).prop('id');
alert(id);
});
View partial:
Button id references a ruby local variable id="<%= name %>"
<% q.categories_name_in.each do |name| %>
<button type="button" class="btn btn-outline-primary btn-lg btn-tag-cat" id="<%= name %>"><%= name %><span class='glyphicon glyphicon-remove'></span></button>
<% end %>
As you've noted, the error is chaining functions in the click listener.
In order to get the id attribute, you can use the jQuery attr function, like:
$("button.btn-tag-cat").click(function(e) {
e.preventDefault();
var id = $(this).attr('id');
alert(id);
$('#' + id).find('span').show();
});
$("button.btn-tag-cat").click(function(e) {
e.preventDefault();
var id = $(this).attr('id');
alert(id);
$('#' + id).find('span').show();
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button class="btn-tag-cat" id="hallo">Press</button>
Here, in your code I will beautify it to see your mistake:
$("button.btn-tag-cat").click(
function(e) {
e.preventDefault();
var id = $(this).prop('id');
alert(id);
id.find('span').show();
},
function() {
id.find('span').hide();
}
);
notice the second function has
function() {
id.find('span').hide(); // right here
}
but the id is not defined yet
try
function() {
var id = $(this).prop('id'); // this first
id.find('span').hide();
}

Why does this jQuery not work in one place?

I have abstracted some jQuery code to handle filtering of tables in my application. In general, the user clicks a link and certain table rows are shown or hidden. The code is below:
var filters = $('ul.filters');
var filtersCount = filters.children().length;
if (filtersCount > 2) {
filters.children(':last-child').css({
'right':'1px'
})
}
var target = filters.data('target');
$('a.filter').on('click', function() {
filters.children().removeClass('active');
$('.filterable').hide();
var $this = $(this);
$this.parents('li').addClass('active');
var visibleStates = $this.data('include-filter').split(" ");
$(visibleStates).each(function(index,state) {
if (state == "all") {
$('.filterable').show();
} else {
$('.filterable' + '.' + state).show();
}
})
if ($this.data('exclude-filter') !== undefined) {
var hiddenStates = $this.data('exclude-filter').split(" ");
$(hiddenStates).each(function(index,state) {
$('.filterable' + '.' + state).hide();
})
}
})
This code is used in five places in my application and works in four of them. By stepping through execution, I know the code does work because it filters the elements but eventually all ".filterable" elements on the page are hidden. I have followed the execution of the code which goes into this part of jQuery:
if ( ret !== undefined ) {
if ( (event.result = ret) === false ) {
event.preventDefault();
event.stopPropagation();
}
}
The line which causes the ".filterable" rows to be hidden is this:
ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler ).apply( matched.elem, args );
Eventually, execution stops on this line:
return event.result;
event.result is undefined if I look at it in the console. Javascript is not really my area of expertise so if anyone can give me a point in the right direction, I would be grateful.
EDIT
I have added the simplest code possible into my table as follows with the same result. Both rows are hidden and don't reappear irrespective of which filter link I click.
<tbody>
<tr class="filterable paid-sick-leave">
<td>From</td>
<td>To</td>
</tr>
<tr class="filterable paid-annual-leave">
<td>From</td>
<td>To</td>
</tr>
</tbody>
The filters look like this. The Ruby code prints out the description of the absence category, downcasing it and replacing spaces with hyphens.
<ul class="filters">
<li class="active">
All Absences
</li>
<% #absence_categories.each do |ac| %>
<li>
<%= ac.description %>
</li>
<% end %>
</ul>
change this click event like below:
$(document).on('click','a.filter', function() {
filters.children().removeClass('active');
$('.filterable').hide();
var $this = $(this);
$this.parents('li').addClass('active');
var visibleStates = $this.data('include-filter').split(" ");
$(visibleStates).each(function(index,state) {
if (state == "all") {
$('.filterable').show();
} else {
$('.filterable' + '.' + state).show();
}
})
if ($this.data('exclude-filter') !== undefined) {
var hiddenStates = $this.data('exclude-filter').split(" ");
$(hiddenStates).each(function(index,state) {
$('.filterable' + '.' + state).hide();
})
}
})
It mean "event.result" is Null you need to test if your event click still exist after you need to debug in the console script as application step by step may be this error caused by no reference class or html.

Use javascript to grab the filename of file selected in Rails form_for file_field before submitting

I am writing code to launch a js popup that will require a user to confirm before they make a specific destructive action by overwriting data with a rails form_for. I already have the js popup and some other logic working, my last remaining task is that I only want this js popup to activate if a file has been attached in a specific file_field on the form. If there is no file attached on that file_field I don't need this to popup.
How can I grab the status of whether or not there is currently a file attached / the filename? Here is my current relevant code. The syntax is Slim:
Form View: Relevant file_field section
tr
= f.fields_for :location_csv, LocationCSV.new do |p|
td = p.label :attachment, "#{#campaign.form_attributes[:location_csv][:label]}"
td.csv-example
- if #campaign.has_entrants_with_locations?
p.alert Warning: Updating Will Delete Location Information For Past Completed Entries
= p.file_field :attachment, accept: "text/csv", class: 'form-control'
Form View: Submit Button Section including some other logic
tr
td colspan='2'= f.submit class: "button success", id: "btn-form-submit", onclick: "destructionWarning(#{#campaign.has_entrants_with_locations?})"
Javascript Snippet
function destructionWarning(status) {
if (status === true) {
if (confirm("WARNING: This update will delete the store location data for #{#campaign.entrants_with_locations_count} campaign entrant#{'s' if #campaign.entrants_with_locations_count > 1}! Cancel to abort.") == true) {}
else {
event.preventDefault();
}
}
}
EDIT: Here is my updated javascript snippet:
var csvElement = document.getElementById("quiz_campaign_location_csv_attributes_attachment");
var csvAttachment = csvElement.value;
function destructionWarning(status) {
if (status === true && csvAttachment != "") {
if (confirm("WARNING: This update will delete the store location data for #{#campaign.entrants_with_locations_count} campaign entrant#{'s' if #campaign.entrants_with_locations_count > 1}! Cancel to abort.") == true) {}
else {
event.preventDefault();
}
}
}
What is the HTML id of the file field input element? You should be able to test the value of the input for an empty string.
Let's assume the id of the file input element id is attachment.
Using plain Javascript:
var file_input = document.getElementById("attachment");
var filename = file_input.value;
if( filename != "" ) {
// There is a file specified
} else {
// There is no file specified
}
Using jQuery:
if( $('#attachment').val() != "" ) {
// There is a file specified
} else {
// There is no file specified
}
If you want to test for the presence of the filename in your destructionWarning function:
function destructionWarning(server_status) {
if (server_status == true) {
var file_input = document.getElementById("attachment");
var filename = file_input.value;
if( filename != "" ) { // user has attached a file
var user_confirmed = confirm("WARNING: This update will delete the store location data for #{#campaign.entrants_with_locations_count} campaign entrant#{'s' if #campaign.entrants_with_locations_count > 1}! Cancel to abort.");
if ( user_confirmed != true) {
// cancel the form submission
event.preventDefault();
}
}
}
}

Append a selected option to a selector

I have two selectors in ERB. They use the Chosen plugin:
<%= select_tag :provinces,
options_for_select(DataHelper::all_provinces_captions.zip(DataHelper::all_provinces_ids)),
{:multiple => true, class: 'chosen-select chzn-select',
:data => {:placeholder => 'Filter Provinces/States'}}
%>
<%= f.select :province_ids,
(DataHelper::all_provinces_captions.zip(DataHelper::all_provinces_ids)),
{ include_blank: true },
{multiple: true, data: {placeholder: 'Filter Provinces/States'} }
%>
I am trying to copy the options from one of the selectors to the other one, while keeping the selected options still selected, however it is not working. Here is the Javascript function I have tried:
var selectedVals = [];
$(".chzn-select").chosen().change(function() {
$("#provinces option:selected").each(function () {
console.log ("this value is " + ($(this).val()));
selectedVals.push($(this).val());
});
$("#education_plan_province_ids").empty();
for (var i = 0; i < selectedVals.length; i++) {
console.log (selectedVals[i] + " selected");
$("#education_plan_province_ids").append($("<option>" + selectedVals[i] + "</option>").attr('selected', true));
}
selectedVals = [];
});
Is there another alternative to attr('selected', true) ?
Here you go:
$(".chzn-select").chosen().change(function() {
$("#education_plan_province_ids").empty();
$("#provinces option:selected").each(function () {
$("#education_plan_province_ids").append($("<option>" + this.value + "</option>").prop('selected', true));
});
});
I am using prop here and getting rid of extra array (which I think is not needed but you can use it if you want). Also you had parenthesis in wrong place for option.

Dynamically changing <div> id on new sets of photos during pagination using infinite scroll and masonry

I am using Infinitescroll to set up pagination. I want to give each new set of photo to have a unique id for the purposes of my modal. Right now, I am able to set the class (static).
itemSelector : '.each_photo_container'
The problem I am having is that when I try to add the div ID to the current photo's id (iterating through each photo), javascript keeps setting the ID of the new photos to the ID of the first photo from the first set.
$newElems.attr('id', '<%=photo[:id]%>');
How do I dynamically add an ID with value photo[:id] to each new photo being loaded by infinitescroll and masonry?
index.html.erb (I understand that the javascript has to be moved to its own file)
<div class="body_container">
<div id="index_header">
<h1>Let's look at <%=params[:search]%>:</h1>
</div>
<div id="photos_container">
<% #photos_array.each do |photo| %>
<div class='each_photo_container' id='<%=photo[:id]%>' >
<%= link_to '#' do %>
<%= image_tag photo[:s_url] %>
<% end %>
</div>
<!-- Masonry/Pinterest Layout + InfiniteScroll/Pagination -->
<script type="text/javascript">
$(function () {
var $container = $('#photos_container');
$container.imagesLoaded(function(){
$container.masonry({
itemSelector : '.each_photo_container',
});
});
$container.infinitescroll({
navSelector : 'div.#page_navigation',
nextSelector : 'div.#page_navigation a',
itemSelector : '.each_photo_container'
},
//trigger masonry on infinitescroll callback and add id to div
function(newElements){
var $newElems = $(newElements).css({ opacity: 0 });
$newElems.imagesLoaded(function(){
$newElems.animate({ opacity: 1 });
$newElems.attr('id', '<%=photo[:id]%>'); //not appending correct ID - keeps appending first element ID
$container.masonry('appended', $newElems,true);
});
}
);
});
</script>
<!-- Load Modal onClick -->
<script type="text/javascript">
jQuery(function() {
$('#<%=photo[:id]%>').click(function (e) {
//ajax call to fetch photo info
var fetch_id = '<%=photo[:id]%>';
var fetch_secret = '<%=photo[:secret]%>';
$.ajax({
type: 'GET',
url: '/photos/fetch_info',
dataType: 'json',
data: { 'id' : fetch_id, 'secret' : fetch_secret },
success: function(data){
//edit innerHTML of basic_modal
$('.basic_modal').html(
//irrelevant code removed for readability
);
//load modal
$('.basic_modal').modal({
overlayClose:true
});
} //end success: function(result)
});
return false;
});
});
</script>
<% end %>
<div class="basic_modal">
</div>
</div><!--End photos_container-->
<div id="page_navigation">
<%= link_to "Next", {:controller => "photos", :action => "index", :page => #page.to_i+1, :search => params[:search]}%>
</div>
</div>
Was able to fix this. Looking at Infinitescroll documentation, you can use this to refer to the current element.
$newElems.attr('id', this.id); fixes the problem and assigns the correct ID.

Categories