How to clear the search parameter that caused the error? - javascript

Let's say I have a page that renders search results depending on the parameters in the URL like so:
https://www.someurl.com/categories/somecategory?brands=brand1,brand2,brand3
Which results in the page showing only brand1, brand2, and brand3 listings. I also have a filter section on the side like so:
[o] Brand 1
[ ] Brand 2
[o] Brand 3
[o] Brand 4
By ticking the items, the URL will get updated with the corresponding parameters. Basically, what happens is that I am fetching data from an API by passing the URL parameters as arguments, which then the server side endpoint takes in to return to me the matching data.
Now the problem is that, if a user types into the URL an invalid parameter e.g.
https://www.someurl.com/categories/somecategory?brands=somegibberish
The server will return an error (which I then display on the page).
However, when I tick one or more of the filters, since what it does is merely append into the URL more parameters, the server will always return an error as the errant parameter is still being sent over:
https://www.someurl.com/categories/somecategory?brands=somegibberish,brand1,brand2
To solve this, currently, when someone clicks a filter and error is not null, I just clear the parameters like so:
componentDidUpdate(prevProps)
if (prevProps.location.search !== location.search) {
if (
someobject.error &&
!someobject.list.length
) {
this.props.history.replace("categories", null);
this.props.resetError();
}
}
}
Which results in the path becoming:
https://www.someurl.com/categories/
But the UX of that isn't smooth because when I click a filter (even if there was an error), I expect it to do a filter and not to clear everything. Means if I have this path previously (has an error param):
https://www.someurl.com/categories/somecategory?brands=somegibberish,brand1
..and I click on brand2 in my filters, the path should become:
https://www.someurl.com/categories/somecategory?brands=brand1,brand2
But am quite stumped as to how to know which of the parameters has to be removed. Any ideas on how to achieve it? Should the server return to me the 'id' that it cannot recognize then I do a filter? Currently, all the server returns to me is an error message.

I agree with SrThompson's comment to not support typing of brands in the app since anything outside of your list results in an error anyway.
Expose an interface with the possible brands for the user to make a selection from.
With that said, here's how you can go about filtering the brands in the request URL.
Convert the URLstring to a URL object and retrieve the value for "brands" query parameter from its search params.
const url = new URL(
"https://www.someurl.com/categories/somecategory?brands=somegibberish,brand1,brand2")
const brands = url.searchParams.get("brands")
Filter brands that are not included in the filter list
const BRAND_FILTER = ['brand1', 'brand2']
const allowedBrands = brands.split(',')
.filter(brand => BRAND_FILTER.includes(brand))
.join(',')
Update the brand query parameter value
url.searchParams.set("brands", allowedBrands)
Then get the URL to be used for the request.
const requestURL = url.toString();

Related

How to get only one user instead of a list?

I try to get from a list of users to only one user and display his profile on another page.
I want to do so with the routerLink and passing on an id of this specific user to the next page.
The routing is working, Im directed to the profile page but when I log the results of the http request I still get back the whole list of users like in the users page instead of the details of one user.
I have tried many things like changing the path of the url in my user.service.ts but that didn't solve the problem I even got 404 request errors when using this path ${this.url}/users/${id}/ instead of ${this.url}/users/?i=${id}/ (where its working).
The api docs is saying though that in order to retrieve one single user its http://1234//users/{id}/ it this scheme while id is an integer. But when I want to apply that scheme I get the 404 error.
Thats why I have to use the ?I= version but there the problem is I only get the full list of users on the next page.
MY CODE:
user.service.ts
// get a user's profile
getUserDetails(id): Observable<any> {
return this.http.get(`${this.url}/users/?i=${id}/`); // why add ?i
}
user.page.ts
// get all users in the users page
getAllUsers() {
this.userList = this.userService.getList()
.pipe(map(response => response.results));
}
user.page.html
<ion-avatar class="user-image" slot="start" [routerLink]="['/','profile', 'user.id']">
<ion-img src="assets/22.jpeg"> </ion-img>
</ion-avatar>
profile.page.ts
information = null;
...
ngOnInit() {
// Get the ID that was passed with the URL
let id = this.activatedRoute.snapshot.paramMap.get('id');
// Get the information from the API
this.userService.getUserDetails(id).subscribe(result => {
this.information = result;
console.log(result);
});
}
It seems like the url is wrong. If it was me I would console.log the url and compare it to the docs. Heres a snippet to try a few variations:
const id = 1;
const options = [
`${this.url}/users/?i=${id}/`,
`${this.url}/users/?i=${id}`,
`${this.url}/users/i/${id}/`,
`${this.url}/users/i/${id}`,
`${this.url}/user/?i=${id}/`,
`${this.url}/user/?i=${id}`,
`${this.url}/user/i/${id}/`,
`${this.url}/user/i/${id}`,
];
for (const option of options) {
try {
const response = await this.http.get(option);
console.log(options, response);
} catch (e) {
}
}
I would also consider dropping the second http request. If the first request returns all the required data you could just store it in a variable on the service.

AngularJs bookmarkable url and query parameters

I'm trying to fix one mistake which one of the previous developer has did. Currently in project we have half-bookmarkable pages. Why half? Because if token has expired user will be redirect to resourse where he has to provide his credentials and on success he will be redirect to previous resource which he has used before. Sounds good for now. The problem here is next, some of resources have server side filtering and highly complicated logic which comes in the end to the one object like this:
param = {
limit: 10,
offset: 0,
orderBy: 'value',
query: 'string query can include 10 more filters'
};
then thru the service it sends a request to the end point
var custom = {};
function data(param) {
custom.params = param;
return $http.get('/data_endpoint', custom)
.then(function (response) {
return response.data;
});
From this part request works fine and response is correct but url isn't. User cannot store current url with search params because url doesn't have it and if user will try to get back to previous page with applied filters he won't be able to do that.
Also there is interceptor in this application, which add one more query param to every api request, because every api request requires some specific validation. This param is always the same.
I have tried to add $location.search(param) exactly to this data service but it breaks the app with infinity loop of login / logout looping, because interceptor stops working and all other request are sending without special query param
Then I thought to add this params inside interceptor like this:
config.params.hasOwnProperty('query') ? $location.search(config.params) : $location.search();
But it still breaks app to infinity loop.
This method adds query to url but doesn't allow to modify it, so if user applied additional filtering, it doesn't send new modified request but sends old one.
if (config.params.hasOwnProperty('query')){
for (var key in config.params){
$location.search(key, config.params[key])
}
}
That's why I decided to ask question here, probably somebody gives an advice how to solve this problem. Thanks in advance.

VSTS query by WIQL does not return requested fields

I'm building a Widget in VSTS and I'm calling the queryByWiql() method from Work Item Tracking rest client.
The query I have is:
queryString = {
"query": "Select [Microsoft.VSTS.Scheduling.RemainingWork]
From WorkItems
Where [System.WorkItemType] = 'Task'
AND [System.State] <> 'Done'
order by [System.CreatedDate] desc"
};
But the result looks like this, where none of the work item actually contain the Remaining Work Information:
This is true for any fields I request; Title, State, Assigned To etc.
The fields I've requested will appear under columns. But none of the work items themvselves will have the information.
Why is this the case? And how can I fix it? Cheers
This is an expected behavior. Currently, there is no way to call the API to return the detailed work item information from a WIQL query directly. You need to get these information in two steps:
Get the ID of the work items from a WIQL which you have done.
Get these work items via Get a list of work items by ID. And you can specify the field to get at this step.
Instruction on WIQL Query page:
After executing a query, get the work items using the IDs that
are returned in the query results response. You can get up to 200 work
items at a time.

Undefined attributes in Parse

I'm using Parse to handle my backend and I'm encountering issues grabbing data from my Parse objects. I've seen many questions similar to this, but none with a straightforward answer.
My User objects have a field called groupsArray which is an array that contains Group objects. Each Group object then contains a field called groupName, which is simply the name of that particular group object.
Here is my trouble. I'm grabbing the current user via
var user = Parse.User.current();
then I grab the groupsArray and the groupNames via
var groupsArray = user.get("groupsArray");
var groupName = groupsArray[i].get("groupName");
Initially this works after I add a group, however, my problem comes after I refresh my browser. After refreshing my browser, all my groupName fields are undefined. When I try and grab their id, it works, but all the personal fields that I created for that object is undefined. When I go to my applications dashboard on parse.com, I see all the objects with their groupNames. Anyone know what's going on?
More detailed code:
Inside groups.js, which calls modelGroups.js:
$('#tester').on('click', function() {
populateSidebar();
});
Inside modelGroups.js:
function populateSidebar(){
var groupsArray = Parse.User.current().get("groupsArray");
for (var i=0; i<groupsArray.length; i++) {
var groupName = groupsArray[i].get("groupName");
console.log(groupName); // ALL of these are undefined after a browser refresh
}
}
And yes, even after refreshing the browser, Parse.User.current() is fetching the correct user, user.id, and username
It seems that the group data needs to be fetched from database again after refresh to me. Never happened on iOS since I enabled local datastore for me.

How do I get the same format for a javascript array and django set on the backend?

I have code that, when a user is logged in, selects recipes that apply to him based on the ingredients (items) he has previously identified identified as possessions.
This code gets the id's of the items the user already has:
if request.user.is_authenticated():
user_items = [possession.item for possession in request.user.possession_set.all()]
user_items_ids = [item.id for item in user_items]
uids = set(user_items_ids)
The following code, which already existed, is where I run into problems...
recipes = [(recipe, len(set([item.id for item in recipe.items.all()]) & uids), recipe.votes) for recipe in recipes]
I created another part of the site that allows people who have not yet signed up to just pick a few ingredients. I do this with some jQuery on the front end, then send the results to the backend:
var ingredient_set = [];
$('.temp_ingredient').each(function(index){
ingredient_set[index] = $(this).attr('id').substr(4);
});
$.get('/recipes/discover', { 'ingredients': ingredient_set },
function(){
alert("Success");
});
The problem is when I receive them on the Django side, with this code:
uids = request.GET['ingredients']
I get the following error:
unsupported operand type(s) for &: 'set' and 'unicode'
Basically, I know they aren't in the same format, but I don't know how to get them to be compatible.
You are sending a JavaScript array in the query string of your GET request. Therefore you should use request.GET.getlist. Just using request.GET[key] gives you the last value for that key.
>> request.GET['foo[]']
u'5'
>> request.GET.getlist('foo[]')
[u'1', u'2', u'4', u'5']
Note that the values are unicode, but you probably need them as integers, so be sure to convert them.
uids = request.GET.getlist('foo[]')
uids = set([int(x) for x in uids])
I'm not sure why my key is actually foo[] and not just foo, but as you get no KeyError, request.GET.getlist('ingredients') should work.

Categories