I have a jQuery search script that uses tabs for the user to define which search type they want to use. When a user searches, a URL is created which is something like #type/query/. However, when you either reload the page, click a result which goes to a different page or return back from a previous page the search results are no longer there. Why could this be and how can I solve this issue? I do not want to use any plug-ins either.
My jQuery code is:
$(document).ready(function () {
$('[id^=type_]').click(function () {
type = this.id.replace('type_', '');
$('[id^=type_]').removeClass('selected');
$('#type_' + type).addClass('selected');
return false;
});
$('#type_search').click();
$('#query').keyup(function () {
var query = $(this).val();
var url = '/' + type + '/' + query + '/';
window.location.hash = '' + type + '/' + query + '/';
document.title = $(this).val() + ' - My Search';
$('#results').show();
if (query == '') {
window.location.hash = '';
document.title = 'My Search';
$('#results').hide();
}
$.ajax({
type: 'GET',
url: url,
dataType: 'html',
success: function (results) {
$('#results').html(results);
}
});
});
var textlength = $('#query').val().length;
if (textlength <= 0) {
$('#query').focus();
} else {
$('#query').blur();
}
});
When you reload the page, the reason that the results are missing is because they aren't in the document source; they've been added to the DOM later.
I reckon you have two choices, the first of which I generally use.
When you execute your search, have either the search criteria or the search results stored at the server so that when the page is next rendered, the results are rendered with it. I use ASP.NET MVC 3 and do this using a PartialView. When I use jQuery to execute the search, it causes the server to render the same PartialView and inserts the resulting HTML fragment into the results div.
Alternatively, you need to fire your jQuery search again when the page is reloaded.
Whether it's better to resubmit the search or to cache the results depends on how expensive the search is and how big the result set is likely to be.
The hash should stay after the reload of the page because it is part of the browser history.
So you can parse document.location.hash to gain knowledge about the selected query type and search.
//$(function() {
if(document.location.hash) {
var hash = document.location.hash;
var split = hash.split('/');
var queryType = hash[1];
var searchTerm = hash[2];
$('#type_'+queryType).addClass('selected');
$('#query').text(searchTerm);
$('#query').keyup();
}
//});
behind your setup routines.
Related
When my MVC5 View loads, I am filling a list for a DropDown on the View and setting the View to only display model records that have a [verified_date] field value older than the cutoff, by default 3 Months:
private InventoryTrackerContext db = new InventoryTrackerContext();
// GET: VerifyAssets
public async Task<ActionResult> Index()
{
List<SelectListItem> intervalList = new List<SelectListItem>();
intervalList.Add(new SelectListItem { Text = "Month", Value = "Month" });
intervalList.Add(new SelectListItem { Text = "Day", Value = "Day" });
intervalList.Add(new SelectListItem { Text = "Year", Value = "Year" });
var cutoffDate = DateTime.Now.AddMonths(-3);
var iNV_Assets = db.INV_Assets.Where(i => i.verified_date < cutoffDate).Include(i => i.Location).Include(i => i.Manufacturer).Include(i => i.Model).Include(i => i.Status).Include(i => i.Type).Include(i => i.Vendor);
ViewBag.intervalList = intervalList;
return View(await iNV_Assets.ToListAsync());
}
Now what I'm trying to implement, is allow users to specify an interval value and interval setting (values 1-31, and [Month], [Day], [Year]):
#Html.DropDownList("NumberValueSelection", Enumerable.Range(1, 31).Select(x => new SelectListItem { Text = x.ToString(), Value = x.ToString() }))
#Html.DropDownList("intervalList")
<span class="glyphicon glyphicon-refresh"> REFRESH</span>
When users click the [REFERSH] button (hyperlink), I want to refresh the view based on user specifications:
SCRIPT:
function newCutoffDate() {
var _value = document.getElementById("NumberValueSelection").value;
var _interval = document.getElementById("intervalList").value;
var data = { value: _value, interval: _interval };
$.ajax({
type: "POST",
dataType: "JSON",
url: '#Url.Action("NewCutoffDateInterval", "VerifyAssets")',
data: data,
success: function (resp) {
alert("Sucess! Value: " + resp.value + " | Interval: " + resp.interval);
},
error: function (resp) {
alert("Error! Value: " + resp.value + " | Interval: " + resp.interval);
}
})
}
CONTROLLER ACTION:
[HttpPost]
public async Task<ActionResult> NewCutoffDateInterval(int value, string interval)
{
var cutoffDate = DateTime.Now.AddMonths(-3);
if (interval == "Month")
{
cutoffDate = DateTime.Now.AddMonths(-value);
}
else
{
if (interval == "Day")
{
cutoffDate = DateTime.Now.AddDays(-value);
}
else
{
if (interval == "Year")
{
cutoffDate = DateTime.Now.AddYears(-value);
}
}
}
var iNV_Assets = db.INV_Assets.Where(i => i.verified_date < cutoffDate).Include(i => i.Location).Include(i => i.Manufacturer).Include(i => i.Model).Include(i => i.Status).Include(i => i.Type).Include(i => i.Vendor);
return View(await iNV_Assets.ToListAsync());
}
This however is not working. When I click the [REFRESH] button (hyperlink), my function executes and my controller action gets called, but the View does not refresh. All that occurs is that I get a return of "Error! Value: undefined | Interval: undefined".undefined` makes sense considering I'm not returning anything, but why is the View not refreshing?
$.ajax({ doesn't modify the DOM nor the window.location. It is an asynchronous request, and therefore happens "behind the scenes" so to speak. No navigation takes place, and the page/DOM is not modified without you explicitly doing so.
If you want the entire page to refresh, you have a couple of options.
Navigation via standard href
Make your link point to a valid href so when they user clicks it, they will be navigated. Use javascript as the user modifies selections to modify the href encoding parameters as query string values. You get the "Refresh" effect just by pointing the URL to the same page, but dynamically updating the href as the user makes selections before hitting refresh. When the user clicks the link, the controller should parse the parameters, and return the same page with new filters applied.
<a href='/VerifyAssets/NewCutoffDateInterval?someParameter=someValue'>Refresh</a>
Navigation via window.location
Keep you <a> as is, but modify your javascript such that instead of making an ajax request, you build a URL as described above, and set it as window.location, causing the page to navigate to the new URL:
// assume you build part after ? dynamically
var url = '/VerifyAssets/NewCutoffDateInterval?someParameter=someValue';
window.location.href = url;
Refreshing partial page
If you create an action that returns a partial view, you can refresh a portion of the page by replacing the content of some element with what is returned:
success: function (resp) {
$('#idOfSomeDiv').html(resp); // replace contents with returned
},
If the request points to a partial view, then resp will be the HTML fragment representing the partial view, and we need to take that and insert it somewhere on the page, which is what $('#idOfSomeDiv').html(resp); does.
There's lots of nuances to each of these approaches that's covered pretty thoroughly elsewhere, so I'm not going to get into that. Some versions of jquery for example require you parse the response before setting it in the DOM. I'll leave it up to you to research your method of choice further.
You're returning a ViewResult to a Javascript call. This won't refresh the view. The better option is to make your existing Controller route an HTTP GET that your refresh link reuses and passes the parameters set in your interface as query string parameters.
EDIT: When I've done this before, I've taken the HTML being returned from async route, and appended it into the DOM. This is different because you're looking to replace the DOM, but it's the same basic idea.
Here's some example Javascript that appends AJAX retrieved HTML into the page
window.EditableList = function (containerSelector) {
var $container = $(containerSelector);
var $list = $container.find("ol").eq(0);
$container
.off(".editable-list")
.on("click.editable-list", "a.add-editor-row", function (e) {
$.ajax({
url: e.target.href,
cache: false,
success: function (html) {
$list.append(html);
ShowHideIcons($("#question-style-dropdown").val());
}
});
return false;
})
.on("click.editable-list", "a.delete-editor-row", function (e) {
$(e.target).parents('li.editor-row').remove();
return false;
});
};
sample controller action
public ActionResult AddFragment()
{
var viewModel = new FragmentViewModel(parameters);
return PartialView("Fragment", viewModel);
}
I understand that I can get the facebook id by doing:
FB.api('/me', function(response) {
alert('Your id is ' + response.id);
});
However, I want to have the user login and then grab that id in a different file so I can handle it. Right now I have:
var id = "";
var fburl = "http://graph.facebook.com/" + id + "?callback=?"
$(function(){
$("#fb-profile-picture")[0].src = "http://graph.facebook.com/" + id +"/picture";
$.getJSON(fburl, function(data){
console.log(data);
$("#name").append(data.name);
$("#user-id").append(data.id);
});
});
and if I manually enter the id in the id var it works however I'd like to be able to grab that response.idas the value and use it in this other javascript file but I haven't figured out how to.
Assuming you
cannot control which of the scripts is executed first
you are working in an environment with a global window object
part one is only executed once
you are using jQuery
making a global and firing an event might be a solution, although not considered best practice.
Script 1:
FB.api('/me', function(response) {
window.fbCustomId = response.id;
console.log(window.fbCustomId);
$(window).trigger('fbResponseLoaded');
});
Script 2:
function renderProfile() {
var fburl = "//graph.facebook.com/" + window.fbCustomId + "?callback=?"
$(function () {
$("#fb-profile-picture")[0].src = "//graph.facebook.com/" + window.fbCustomId + "/picture";
$.getJSON(fburl, function (data) {
console.log(data, window.fbCustomId);
$("#name").append( $('<span>').text(data.name) );
$("#user-id").append( $('<span>').text(data.id) );
});
});
}
if (window.fbCustomId) {
renderProfile();
} else {
$(window).on('fbResponseLoaded', renderProfile);
}
I have the following link that passes an id to my controller to render a report.
Print Report
I would like to assign this value id in the link above to the result I have returned from the database in the call below....
// Global variable
var DocumentID = null;
$('#Save').click(function(e) {
if (document.forms[0].checkValidity()) {
e.preventDefault();
$.ajax({
url: "/Home/SaveDetails",
dataType: "json",
type: "POST",
data: ko.toJSON(viewModel),
contentType: "application/json;charset=utf-8",
success: function(result) {
if (result > 0) {
//Assign return value to DocumentID
DocumentID = result;
alert("This work request has been successfully saved in database. The Document ID is: " + result);
} else {
alert("The Work Request was not saved, there was an issue.");
}
},
complete: function() {
// Hide loading image.
},
error: function(jqXHR, textStatus, errorThrown) {
// Handle error.
alert(errorThrown);
}
});
} else {
alert("Form is not valid");
}
});
The call above works and returns a DocumentID and displays this in an alert with success. The link above works if the id has a hard-coded value; I would just like to make this value dynamic.
if (result > 0) {
//Assign return value to DocumentID
var DocumentID = result;
var href = '#Url.Action("GetReport", new { type = "PDF", id =' + DocumentID +'})';
$("a:contain('Print Report')").attr('href', href);
}
The above suggestions will generate an error for an unsupported pseudo, in this case 'contain' which is not available or known to the anchor tag. There is also an error with the syntax of putting the DocumentID in the Url.Action. I was not able to get this to work, instead I found another error: Too many characters in literal.
Instead give your anchor an id and find that id using jQuery and replace it's href attribute, this is done in the second line of code under Javascript.
html:
<a href="#" **id="Report"**>Print Report</a>
Javascript:
var DocumentID = result; var href = '#Url.Action("GetReport")?type="PDF"&id=' + DocumentID + '';
$("#Report").attr('href', href);
Take note of two things. The URL is formed and the anchor tag is found differently versus previous suggestions.
This has been tested and works for parameters of type string and int, respectively in your callback function to handle getting the report. If you want two strings then add an additional double-quote around the DocumentID like this: id=" ' + DocumentID + ' "';
in your ajax-success handler just set the href of the anchor to whatever you want
var newHref = '#Url.Action("GetReport", new { type = "PDF", id = '+DocumentID +'})';
$('a').attr('href',newHref);
I have some words on a page that display "present" or "absent" that a user can click to toggle between being present or absent.
When the word is set to "absent" I want that text to be red.
The word represents a bool and is updated on screen using the following code:
<script type="text/javascript">
absentText = $.trim('#MyApp.Resources.MyAppResource.Absent_Text').toLowerCase();
presentText = $.trim('#MyApp.Resources.MyAppResource.Present_Text').toLowerCase();
updateAttendanceUrl = '#Url.Action("UpdateAttendance", "Attendance")';
</script>
Where MyAppResource.Absent_Text = absent the page displays fine with the word, "absent" on the page.
When I change MyAppResource.Absent_Text to read "absent" my page literally displays <span style="color:red">absent</span>
Here is a sample of my view source:
<td><span style="color:red">absent</span></td>
So somehow my < and > symbols are getting taken away.
How can I change my code so that when the word on my screen is written as "absent" it is colored red?
Is there a simpler way to just color any text on the screen that matches "absent" red?
For reference, here is the rest of the javascript from my page:
var userId;
var attendanceDay;
var isPresent;
var updateAttendanceUrl;
var absentText;
var presentText;
var courseId;
$(document).ready(function (event) {
$('.attendance').live('click', function () {
userId = $(this).parents('tr').attr('id');
if (userId != '') {
attendanceDay = $(this).attr('id');
isPresent = $.trim($(this).find('span').text().toLowerCase());
courseId = $(this).parents('tbody').attr('id');
$(this).find('span').addClass('currentClass');
if (isPresent == absentText) {
UpdateAttendance(1);
} else {
UpdateAttendance(0);
}
} else {
event.preventDefault();
}
});
});
function UpdateAttendance(present) {
url = updateAttendanceUrl;
$.ajax({
type: "POST",
url: url,
data: "userId=" + userId + "&attendanceDay=" + attendanceDay + "&courseId=" + courseId + "&present=" + present,
success: function (data) {
if (isPresent == absentText) {
$('#' + userId).find('.currentClass').text(presentText).removeAttr('class');
} else {
$('#' + userId).find('.currentClass').text(absentText).removeAttr('class');
}
return true;
}
});
}
What your looking for is called unescape or htmldecode. There are various topics available on SO already. Here is one.
I have a jQuery search script that uses tabs for the user to define the search type they want. A tab is selected as the default by using $('#type_search').click(); however this causes a problem when refreshing a results page. If a different search type is selected and then the page is refreshed, the default tab is automatically selected so it doesn't return the correct results even though the page URL says it is correct.
My question is, how can I define the default tab from the section in the URL if a query is active and if there is no active query use the default tab? I hope you can understand what I'm saying.
My jQuery code is:
$(document).ready(function () {
$('[id^=type_]').click(function () {
type = this.id.replace('type_', '');
$('[id^=type_]').removeClass('selected');
$('#type_' + type).addClass('selected');
return false;
});
$('#type_search').click();
$('#query').keyup(function () {
var query = $(this).val();
var url = '/' + type + '/' + query + '/';
window.location.hash = '' + type + '/' + query + '/';
document.title = $(this).val() + ' - My Search';
$('#results').show();
if (query == '') {
window.location.hash = '';
document.title = 'My Search';
$('#results').hide();
}
$.ajax({
type: 'GET',
url: url,
dataType: 'html',
success: function (results) {
$('#results').html(results);
}
});
});
if (window.location.hash.indexOf('#' + type + '/') == 0) {
query = window.location.hash.replace('#' + type + '/', '').replace('/', '');
$('#query').val(decodeURIComponent(query)).keyup();
}
var textlength = $('#query').val().length;
if (textlength <= 0) {
$('#query').focus();
} else {
$('#query').blur();
}
});
Ah, I had that problem too. It's pretty simple. On page ready you just take the anchor from the URL and simulate a click.
$(document).ready(function() {
url = document.location.href.split('#');
$('#'+url[1]).click();
});