How can I get jade/express to output the full path in anchor links? - express

I would like my links to be full absolute paths to the resource being linked without me having to hard code the scheme and URI to the resource. I wish to do this in relation to using itemprop='url' on links to have the full url appear in the href attribute.

There are several approaches. The first one I would suggest is a basic helper function passed to jade during the rendering. Perhaps bound to the current request:
In your express code:
function absolute(req, url) {
//you'll need more logic here, but this is the concept
return req.originalUrl + url;
}
res.render("somePage", {absolute: absolute.bind(null, req)});
In your jade markup:
a(itemprop=url, href=absolute(url))
//- This is assuming "url" is a variable with a string like "/cars/42"

Related

Is there a named routes and default params equivalent for Razor Pages page routes?

I have a JobPosts/Index page with multiple GET parameter bindings to allow filtering: let's take CityId and IsRemote for example. I don't want these to be passed as query string parameters, instead I want to use friendly routes for them. So I have defined these:
options.Conventions.AddPageRoute("/JobPosts/Index", "cities/{cityId}/jobs");
options.Conventions.AddPageRoute("/JobPosts/Index", "remote-jobs");
options.Conventions.AddPageRoute("/JobPosts/Index", "jobs");
The routes work just fine when I type them in the browser and the CityId one is bound properly, but two things are missing.
First, there is no way to specify a default value for my IsRemote param, which I want to set to true ONLY when using the remote-jobs URL.
And second, when trying to generate a URL like this:
<a asp-area="" asp-page="/JobPosts/Index" asp-route-cityId="#Model.CityId"></a>
I get the following URL:
https://localhost:44391/jobs?cityId=2265885
When what I actually expect is:
https://localhost:44391/cities/2265885/jobs
So it looks like the tag helper or the part responsible for constructing the URL doesn't look at all at the different routes to try and get a best match based on the list of parameters. Actually, it will always use the last page route defined for that page.
Nor do I have the option anywhere to specify a route name for the page route and then use asp-route to explicitly say which route I want.
Any ideas how to achieve that? Or if it's something that's on the roadmap for Razor Pages?
EDIT: Hardcoding the href is not an option. I want this to go through the proper routing services as there are other things to be done as well, like generating culture-specific URL for non-english users (eg. {cultureId}/cities/{cityId}/jobs - this is done through route conventions. Hardcoding the href would obviously bypass that.
There is a easy way to set IsRemote default value.
public bool IsRemote { get; set; } = true;
This tag asp-page will link to Page /JobPosts/Index.csthml directly,
https://localhost:44391/JobPosts?cityId=2265885
= https://localhost:44391/JobPosts/Index?cityId=2265885
If you are looking forward the URL https://localhost:44391/jobs?cityId=2265885
you could try this a tag to request.
Go to JobPosts
———————————————————————————————
Using a middleware to handle /remote-jobs
app.Run(next => async context =>
{
if (context.Request.Path == "/remote-jobs")
{
return View with default IsRemote
}
});

Friendly URL for RazorPage with query string

I would like to create friendly routes that map to different query string values of a single Razor Page and it's base GET handler. I'd be fine with switching the query string to being a part of the route as well. The idea is we have a single page that loads a file list and can filter. I'd prefer it if the URL was more straight forward. If it's not possible I could just go with /Files/In or /Files/Out
Example
/Files?direction=In -> /In
/Files?direction=Out -> /Out
Is there any way to do something like this?
You can use route data parameters which are defined in a Route Template as part of the #page directive in the .cshtml file :
#page "{direction?}"
Then you can access the route parameter value in OnGet method of your file page :
public void OnGet(string direction)
{
if (!string.IsNullOrEmpty(direction))
{
//filter files based on direction
}
}
You can pass direction value as /Files/In or /Files/Out , without filter directly use /Files .

Recursive/Exploded uri variable with restlet

Does Restlet support exploded path variable (reference to URI Template RFC)?
An example would be /documents{/path*} where path can be for example "a/b/c/d/e".
This syntax doesn't seem to work with Restlet.
I'm creating a folder navigation api and I can have variable path depth, but I'm trying to have only one resource on the server side to handle all the calls. Is this something I can do with Restlet? I suppose I could create a custom router but if there is another way to do this I would like to know.
Thanks
It is possible to support this using matching modes.
For example:
myRouter.attach("/documents{path}",
MyResource.class).setMatchingMode(Template.START_WITH);
Hope this helps!
I'm doing the following
myRouter.attach("/documents/{path}", MyResource.class).setMatchingMode(Template.START_WITH);
Now I do get inside the resource GET method, but if I request the value of the path variable, I only get the first part (for example, /documents/a/b/c, path returns "a".) I use getRequest().getAttributes().get("path") to retrieve the value. Am I doing something wrong ?
Mathieu

Implementing Google Custom Search with filtering

I have to implement a page with multiple google-powered search forms. We have a license from Google for CSE, and this is the situation:
I have a search form that's present at the top of every page that performs a simple search and displays the results in a separate page. This works.
I have a particular page that, in addition, shows another two search forms: one should filter articles by category, another should filter articles by category and restrict the result to a certain month. I have added a meta key with the publication date to each article for this.
I have gotten a bit lost in the documentation, though: if I add
<gcse:searchbox-only resultsUrl="/[site]/stat/search/google_search_results.html"></gcse:searchbox-only></div>
to the page, I can't filter the results. If I start to meddle with a CustomSearchObject, I don't see an option to show results on a different page.
For category-based filtering, I've tried appending
more:pagemap:metatags-taxonomies:news
to the query argument in the results page URL, and it does work, but I don't understand how to inject this to the form.
For restricting based on dates, I tried adding
&sort=more:pagemap:metatags-pubdate:r:YYYYMMDD:YYYYMMDD
but haven't been able to make it work. Getting the XML does work:
http://www.google.com/search?q=intitle:[mysite]%20more:pagemap:metatags-taxonomies:News&sort=metatags-pubdate:r:20120401:20120830&cx=[mykey]client=google-csbe&output=xml
returns correct results.
Is there documentation that doesn't assume so much? All I find are code snippets without context. I've checked Filtering and sorting, Custom Search Element Control API, and of course this site, but I can't put all the pieces together.
I managed to implement what I wanted. In the search page, I built simple forms pointing to my results pages (this might not be doable if you must implement google branding), and in the results page I put the following:
(in the <head>)
<script src="http://www.google.com/jsapi"></script>
<script>
// This function extracts the query from the URL (if GET) or builds a search query.
// Code removed to simplify the example.
function buildQuery () {
return '<?php echo $_POST['q'];?> more:pagemap:metatags-taxonomias:News'); // injecting the taxonomy metatag filter
}
google.load('search', '1', {language : 'es'});
google.setOnLoadCallback(function() {
var customSearchOptions = {};
customSearchOptions[google.search.Search.RESTRICT_EXTENDED_ARGS] = {'sort':'metatags-pubdate:d,metatags-pubdate:r:<?php echo $_POST['startdate'];?>:<?php echo $_POST['enddate'];?>'}; // these come from the POST request, are processed earlier in the script.
var customSearchControl = new google.search.CustomSearchControl('XXXXXXXXXXX', customSearchOptions); // Put your own App key here.
customSearchControl.setResultSetSize(google.search.Search.FILTERED_CSE_RESULTSET);
var drawOptions = new google.search.DrawOptions();
drawOptions.enableSearchResultsOnly(); // I don't want the search box here
customSearchControl.draw('cse-results-press', drawOptions);
var query = parseQuery();
if (query) {
customSearchControl.execute(query);
}
}, true);
</script>
In the <body>:
<div id="cse-results-press">Loading...</div>

Passing variables into JavaScript in ExpressJS/PassportJS/Jade app

This is essentially a continuation of the question here: Nodejs Passport display username.
app.get('/hello', function(req, res) {
res.render('index.jade', { name: req.user.username });
});
So users log in via PassportJS, and goes to index.jade, which contains #{name} in the body, which will be replaced by the value of req.user.username.
Question: Is it possible to use the value of req.user.username in index.jade's JavaScript? I tried assigning its value to a variable but it doesn't work.
I have been using the trick of having a hidden input with #{name} as value:
input(type='hidden', id='variableName', value='#{name}')
Then JavaScript can access this value using:
$("#variableName").val()
This works. But does it have any potential downside like security issues? What is the right way to do this?
You have a few options. One of them is what you did and put the value inside you html. You can also solve it by doing:
script
window.name = #{name};
This will create an inline script that sets the variable. The other option you have is using ajax. That means you probably need to make an extra route to reply to that request.