I have a search results page in a PHP site that returns a list of results using pagination. The URL looks like this:
findProducts.php?action=searchAssets&orderNumber=xxxx&productName=zzz&skip=20
I have a select menu that allows the user to modify/filter the search results which triggers a script like this:
$(document).ready(function() {
$('#productType').change(function() {
window.location.href = window.location.href + '&productType=' + $(this).val();
});
});
This is working well except for one thing - I need to reset the 'skip' parameter to 0 for the new filter search as the pagination values from the previous search won't be valid or applicable. Is there a way I can change:
skip=20
to:
skip=0
as part of this script?
You could do a RegExp replace on the URL:
window.location.href = window.location.href.replace(/((?:\?|&)skip)=\d+/, '$1=0') + '...';
(untested)
Note that you should do the same with the productType because otherwise you'll add it again and again.
Better solution would possibly be to have a base URL and then add all necessary parameters instead of doing search and replace...
You can get the query from the URL by splitting the URL using ?
This will give you the base url in the first index and the query in the second.
You can then get the query parameters by splitting the query using &.
You can loop through all of the parameters checking if it is the skip parameter. If the parameter is the skip parameter push your new value to an output array. Otherwise push the unchanged parameter to an output array.
You can then use join to join all of your output elements using & to reconstruct the query and return your original base url with your new query string.
<script>
function fixQuery(qstr) {
var parts = qstr.split('?');
var query = parts[1];
var a= query.split("&");
var out=[];
for (var i = 0; i < a.length; i++) {
var b = a[i].split('=');
if(decodeURIComponent(b[0])=="skip")
{
out.push("skip=0")
}
else {
out.push(a[i]);
}
}
return parts[0] + '?' + out.join("&");
}
var result= fixQuery("http://example.com/findProducts.php?param1=test+thing¶m2=hello&skip=10");
console.log(result)
//http://example.com/findProducts.php??param1=test+thing¶m2=hello&skip=0
</script>
Related
The purpose of this code is to open two different tabs where one tab is nested inside main tab. When user click a link which passes a query string hash values like the following
http://127.0.0.1:5500/products/virtual-machines.html#Get_Started#v-pills-02-tab
I need to open both tabs at once when page loads.Bootstrap 5 is the plugin used for. I tried using the following code.
var hash = location.hash.split('?')[0];
console.log(hash);
if (hash) {
var triggerEl = document.querySelector("#" + hash + '');
triggerEl.click();
}
result
#Get_Started#v-pills-02-tab
I need to slipt in two var
Get_Started
v-pills-02-tab
Your example code is splitting on a question mark (?), which doesn't exist in your hash.
Perhaps you could write your hash as a comma separated list, the first item in the list would be the parent tab element id, and the 2nd item would be the child tab element id, etc.
http://127.0.0.1:5500/products/virtual-machines.html#Get_Started,v-pills-02-tab
Then parse it, splitting on the comma.
// substring out the leading '#'
// and convert the comma-separated items into an array
var tabIds = location.hash.substring(1).split(',');
if(tabIds) {
var $tab = $('#' + tabIds[0]);
// Ensure that the element exists before clicking it
if($tab.length > 0) {
$tab.click();
// Check for subsequent tab-ids
if(tabIds.length > 1) {
var $subTab = $('#' + tabIds[1]);
if($subTab.length > 0) {
$subTab.click();
}
}
}
}
(Sorry if you're allergic to jQuery. It shouldn't be difficult to translate it to vanilla JS.)
So I have 3 links: 1, 2 and 3 and they all go to the same page and each have a function (1(), 2() and 3()) I want to, when you go to one of those pages from the home page, to go to the 123.html and run 1() or 2() depending on what button they clicked.
I've tried this:
<li><span>Link1</span></li>
But it didn't run the function at all. And I want to have all of them like this:
<li><span>Link1</span></li>
<li><span>Link2</span></li>
<li><span>Link3</span></li>
You cannot pass javascript to a page like this unless the page you are going to is looking for the javascript query string in the url.
It would be better to send a query string variable such as ?action=Link1 and then have some javascript check for the "action". You could then run a function based on what the action is.
There are a lot of functions you can find that will do this for you, by looking at the window.location variable
This is not the way of doing.
What you could do is add a parameter in your link, something like
?function:1.
You can then extract the parameter on your 123.html page like this :
var url_string = window.location.href
var url = new URL(url_string)
var c = url.searchParams.get("function")
c will have the value of 1, 2 or 3. With that you can make a switch statement and select which function to execute :
switch(c) {
case 1:
function1()
break
}
I do not recommend working like this but if you want to do it like that here you go.
Based on a similar question you can't (1st answer), but expanding on this answer you can do something like this
a.html
<li><span>Link1</span></li>
b.html
<script>
// get hash from url
var hash = window.location.hash;
// clean
hash = hash.replace('#', '');
hash = hash.replace(';', '');
hash = hash.replace(new RegExp("%20", "g"), "");
const fb = (a, b) => {
console.log(a);
console.log(b);
}
// Option 1:
/**
* parse all parameters from string to an array
*/
const parseParams = (str) => {
let params = str.split(/[/(/)]/)[1].split(',');
for (i=0; i < params.length; i++) {
params[i] = params[i].replace(new RegExp("'", "g"), "");
}
return params;
}
// check for existing function - parse only the function name
switch(hash.substring(0, hash.indexOf("("))) {
case "fb":
var params = parseParams(hash);
fb(...params);
break;
default:
break
}
// Option 2 (easy solution but try to avoid this):
eval(hash);
</script>
I have not been able to find a working example or a good explanation of how I can achieve the following: (I would appreciate if anyone can point me in the right direction.
I have a query string: **"/api/bla?sources=[1,2]&plans=[1,2]&codes=[1,2,3]"**
I will be updating the query string via either javascript or jquery when certain events occur on my page, doesnt matter which.
For example, there is a multi select dropdown on the page which houses [sources] and [plans] and [codes]... These dropdowns have IDs which i am to update my request url with upons selecting items in teh dropdowns.
When a source with ID "3" is selected from the dropdown (or checkbox, doesnt matter what page controls are being used) the query string parameter sources[1,2] will need a "3" appended. Likewise then if the item with an ID of "2" is unselected, it will likewise be removed from the query string leaving the new string as sources[1,3]
I am somewhat new to javascript/jquery and especially more advanced string manipulation. I have been attempting to recreate something to demonstrate this and have gotten to the following which is not fully working.
Basically my initial if statement works as intended, but the moment the else is hit (when another ID needs to be added to an existing model in the query string - like a second ID for [sources] or [codes]) it returns wonky output - seeng as I couldnt get the right formula to update everything correctly.
//TIMEMTABLE QUERY
function updateCalendar(filter_id, filter_element) {
//Run through the filter checks before making final call to query and update timetable?
//GET THE MODEL/OBJECT NAME
var queryName = filter_element.attr('data-owner');
//GET THE IDs //this is either an array of all selected IDs or a single id which is used in the else statement
var queryId = filter_element.attr('value');
var queryIds = $('#'+filter_id).val();
var modelCheckIndex = requestString.toLowerCase().indexOf(queryName.toLowerCase());
//build a request string
if (modelCheckIndex < 0) {
console.info('ADD MODEL TO QUERY STRING');
requestString = requestString + "&" + (queryName.toLowerCase() + "[" + queryIds + "]");
console.log(requestString);
}
else{
console.info('UPDATE MODEL ON QUERY STRING');
var position = requestString.toLowerCase().indexOf(queryName.toLowerCase());
//requestString = requestString.substr(modelCheckIndex -1, requestString.length -1) + "," + queryId + "]";
requestString = requestString.slice(modelCheckIndex.indexOf("]"), modelCheckIndex) + "," + queryId;
console.log(requestString);
}
//MAKE THE API CALL USING CREATED QUERY STRING
}
If anyone has any examples or fiddles lying around I would also appreciate it.
Fiddle I am trying to get to work
It looks like you are just having trouble parsing and updating a query string. In which case, I have a function I've been using for that (thank you Google)
function getUriParams(string) {
var params = {},
queryString = string.slice(string.lastIndexOf('?')).substring(1),
regex = /([^&=]+)=([^&]*)/g,
m;
while (m = regex.exec(queryString)) {
params[decodeURIComponent(m[1])] = decodeURIComponent(m[2]);
}
return params;
}
The input is your requestString and the output is an object of key value pairs of the query string.
To make the object a string, jQuery makes it easy with $.param().
//get key value pairs
var obj = getUriParams(requestString);
//make query string
var str = $.param(obj);
I suggest to change the logic a bit. I would use some data storage for the wanted parameter and rebuild the request string every time when it's necessary, like the below example.
It is much more better, than rebuild the string each time when some value has changed.
var data = {
sources: [1, 2],
plans: [],
codes: [1, 3, 4]
};
function buildStr() {
function get(key) { return key + '=' + JSON.stringify(data[key]); }
return '/api/bla?' + ['sources', 'plans', 'codes'].map(get).join('&');
}
document.write('<pre>' + buildStr() + '</pre>');
I have implemented searchbox using jQuery. Here is the code which sends search term and
after that I receive Json which I use to make list of matched searched items.
The problem is that on each keyup I delete all matched items :
$("#realPlaceForSearchItems").html("");
because if I don't that I get duplications when searching for product if I enter "pro" and then type "d". (I am appending list items to the list) Is it possible to achieve that I somehow just delete elements that do not match "prod" (which previously matched "pro" ofcourse) and that elements that match prod stay untouched after typing "d".
$("#searchInput").keyup(function () {
$this = $(this);
$('#realPlaceForSearchItems').show();
$("#realPlaceForSearchItems").html("");
var seachedTerm=$this.val();
if ($this.val().length> 2)
{
$("#realPlaceForSearchItems").html("");
$('#realPlaceForSearchItems').show();
$.ajax({
type: "POST",
url: ROOT + "Filter/Search/",
data: {term: $this.val()},
success: function (data)
{
var Link = $("#searchTemplate>li>a");
var placeForProductId=$("#searchTemplate>li>a>input");
var placeForPicture = $("#searchTemplate>li>a>div>img");
var placeForProductName = $("#searchTemplate>li>a>div>div");
var placeForPrice= $("#searchTemplate>li>a>div>span");
$.each(data.productsWereSeached, function () {
console.log("sddsd", data.totalrows);
var imagesFolder="/Content/images/";
var pathToProduct="/ProductDetails/Index/"
var slash = "/";
Link.attr("href", pathToProduct + this.Id);
placeForProductId.val(this.Id);
if (this && this.Picture) //for the case there is no any picture there would be error cant read propery or undefined
placeForPicture.attr("src", imagesFolder + this.Id + slash + this.Picture.FileName);
else
placeForPicture.attr("src", "");
placeForProductName.html(this.Name);
placeForPrice.html((parseFloat(this.Price) / 100.0).toString() + " kn");
$listItem = $("#searchTemplate").html();
$("#realPlaceForSearchItems").append($listItem);
});
$("#nOfMatchedProducts").val(data.totalrows);
if (data.totalrows > 2)
{
var searchurl="/Search/ShowMoreSearched?term="
$showMoreItem = $("#showMoreItem").html();
$("#showMoreItem>li>a").attr("href",searchurl+seachedTerm);
$("#realPlaceForSearchItems").append($showMoreItem);
}
},
failure: function ()
{
}
});
}
});
$.each(data.productsWereSeached, function () {
if($('a[href="'+pathToProduct + this.Id+'"]').length == 0) {
console.log("sddsd", data.totalrows);
var imagesFolder="/Content/images/";
var pathToProduct="/ProductDetails/Index/"
var slash = "/";
Link.attr("href", pathToProduct + this.Id);
placeForProductId.val(this.Id);
if (this && this.Picture) //for the case there is no any picture there would be error cant read propery or undefined
placeForPicture.attr("src", imagesFolder + this.Id + slash + this.Picture.FileName);
else
placeForPicture.attr("src", "");
placeForProductName.html(this.Name);
placeForPrice.html((parseFloat(this.Price) / 100.0).toString() + " kn");
$listItem = $("#searchTemplate").html();
$("#realPlaceForSearchItems").append($listItem);
}
});
Psst... I'm assuming you also want to limit calls to the server and that your search result list is not wildly huge!
So! Benefit to your current approach is you don't have to manage/compare any existing data set. This makes things easier when a search for "pro" changes to a search for "cro" or any other change that makes the previous AJAX call irrelevant. But, like you said, it leaves you with this clear then re-add items inefficiency when you search for "prod" after "pro".
Idea:
Store the most recent AJAX call criteria in a global.
If new search value includes the latest AJAX search value, filter/hide items in the existing data set which do not match the new criteria. Do not perform a new search.
If new value does not include the latest AJAX search value: clear current data set, update AJAX search value, execute new AJAX call
Pass the index from $.each (http://api.jquery.com/jQuery.each/) into your function, then use it to select the search result you will replaceWith (http://api.jquery.com/replaceWith/) the element you just built. In using this method, your four LI elements within the search results UL must exist before a search.keyup is executed.
Do this by changing two lines...
$.each(data.productsWereSeached, function (index) {
... all of the existing code in the loop stays the same except ...
$("#realPlaceForSearchItems LI:eq(" + index + ")").replaceWith($listItem);
});
I am currently trying to parse parameters from a path to a JavaScript file (inside a script tag). At the moment I know which parameters I expect to be there but instead of looking for the expected params I would rather like to just extract all params given.
Example of the script tag which includes a JavaScript file:
<script type="text/javascript" src="https://url/widget.js?param1=A¶m2=bb></script>
At the moment I'm just doing this (seperately for each parameter):
jQuery('script').each(function() {
var script = this;
if (!script.src) {
return;
}
var matchKey = script.match(/https\:\/\/url\/widget\.js\?param1=([A-Z]+)/);
if (matchKey) {
oSettings.param1 = matchKey[1];
}
}
So what I need is a regex that extracts both the name of the parameter and the value from the included sript.
Thanks for the assistance!
This tested function works:
function parse_query_vars(text)
{ // Extract name=value pairs from URL query string.
// Empty object to store name, value pairs.
var qvars = {},
// Capture non-empty query string in $1.
re_q = /\?([^#]+)/, // From '?' up to '#' or EOS.
// Capture variable name in $1 and value in $2.
re_nv = /([^=]+)=([^&]*)(?:&(amp;)?|$)/gi,
// Match array for query string and va=val pairs.
m = text.match(re_q),
// Query string plucked from URL
q = '';
// If there is a query string, copy to q var.
if (m) q = m[1];
while (m = re_nv.exec(q)) {
qvars[m[1]] = m[2];
}
return qvars; // Return results in object
}
It first extracts any query string from the URL, then iteratively parses out name=value pairs and returns the results in an object. It handles name value pairs separated by either & or & and works if the URL has a #fragment following the query.
Use something like this, or this, or this.
They're not all regex solutions, but then you don't necessarily need a regex. That was a detail that could probably have been left out of the question.
Hope that helps.
(This isn't actually tested)
var scripts = document.getElementsByTagName("script"), i = scripts.length;
var reMatch = /https\:\/\/url\/widget\.js/, path;
// find the correct script
do {
path = scripts[i--].src;
}
while (!reMatch.test(path));
var map = {}, pairs = path.substring(path.indexOf("?") + 1).split("&"), atoms;
i = pairs.length;
// extract the name-value pairs
while (i--) {
atoms = pairs[i].split("=");
map[decodeURIComponent(atoms[0])] = decodeURIComponent(atoms[1]);
}