How to use routablepageurl tag in wagtail HTML template - wagtail

I reviewed official docs for several times and still quite confusing in regards to how to use routablepageurl tag exactly.
below are from official doc
wagtail.contrib.routable_page.templatetags.wagtailroutablepage_tags.routablepageurl(context,page, url_name, *args, **kwargs)
routablepageurl is similar to pageurl, but works with pages using RoutablePageMixin. It behaves like a hybrid between the built-in reverse, and pageurl from Wagtail.
page is the RoutablePage that URLs will be generated from.
url_name is a URL name defined in page.subpage_urls.
Positional arguments and keyword arguments should be passed as normal positional arguments and keyword arguments.
Q1: How the required parameter context is provided?
Q2: What exactly page and url_name stands for ? I did not see an attribute (subpage_url) in page model. Official doc explanation is quite confusing.
Q3: Why sometimes category.slug is used as a argument for routablepageurl template tag as show in this blog post.
{{ category.name }}

Overview
The docs section for the routablepageurl template tag is quite short and it can come across as a bit confusing due to it being quite densely packed with references to concepts in Wagtail and Django.
Let's unpack the line:
routablepageurl is similar to pageurl, but works with pages using RoutablePageMixin. It behaves like a hybrid between the built-in reverse, and pageurl from Wagtail.
Firstly, this is a custom template tag which is a function that takes some known arguments/params in a specific order that can be made available to template tags. The important thing to note here is that context is something that gets passed into the template tag function call but you do not have to pass it in explicitly when using the template tag.
Understanding this requires a bit of an understanding of how Django's URL system works and it would be good to read through the Django docs on this topic https://docs.djangoproject.com/en/3.2/topics/http/urls/
pageurl here is a reference to a different template tag that has similar behaviour, you can view the docs for the pageurl template tag.
routablePageMixin is a Page mixin that allows the use of multiple sub-page routes to be made available, each with a name with a decorator like #route(r'^past/$').
Behaves like reverse is a reference to the django.urls.reverse function which takes a URL name and will return the URL. Reverse provides a way not only to get a URL based on a name but to pass arguments in that will build up the full URL based on those arguments.
In all of these references, the concept of a name is also a Django concept where when you declare URL patterns (e.g. all 'blog/DD-MM-YYYY' pages) with a name to reference them elsewhere.
Specific Answers
Q1: How the required parameter context is provided?
context is provided by default for all template tag function calls.
Q2: What exactly do page and url_name stand for?
page is a modal instance, this would be the page that is using RoutablePageMixin.
url_name is the name of the URL pattern as defined in your page, this can come across a bit unclear but it is the function name that is used to create the sub routes, in the code example below (from the docs), the url name will be current_events.
class EventIndexPage(RoutablePageMixin, Page):
#...
#route(r'^$') # will override the default Page serving mechanism
def current_events(self, request):
"""
Q3: Why can category.slug be used as an argument for this template tag
This is an example of passing extra params/arguments to the template tag, these in turn get passed to the URL resolver system to build up a URL.
For example, in the code snippet below (from the blog post) if the category.slug was 'coffee shops' (a category), this is what will happen:
Given the tag usage {{ category.name }}
The blog_page will be a variable that is the current page instance
The "post_by_category" says to find the URL sub-route with the name (method name) of post_by_category.
Any other params after that will be used to build the URL based on the URL pattern, let's say that category.slug is 'coffee-shops' (the slug being a URL valid string) of the category 'Coffee Shops'.
In the code below the pattern is r'^category/(?P<category>[-\w]+)/$', where the <category> (angled brackets) is a variable usage, the URL resolver will inject the slug and build a URL path of 'category/coffee-shops'
class BlogPage(RoutablePageMixin, Page):
description = models.CharField(max_length=255, blank=True,)
#...
#route(r'^category/(?P<category>[-\w]+)/$')
def post_by_category(self, request, category, *args, **kwargs):
self.search_type = 'category'
It is important to understand that ANY key word arguments or arguments can be passed in to the template tag and these values will in turn be passed to the URL resolver which reads the URL pattern syntax and attempts to build a URL based on how those arguments are used in the pattern.

Related

How to concatenate two variables and assign to the label attributes of lightning-card in lightning web component

I have a lightning-card in lightning web component (LWC) and want to set the label attribute with two different variables. Although this can be done through the controller but I want to do this in html file itself.
As in the code snippet, I am assigning {cardTitle} as a title, but I have another variable {totalCount} and want to concatenate the totalCount along with the cardTitle here. So lightning-card should have title like "{cardTitle}{totalCount}".
<lightning-card title={cardTitle}></lightning-card>
//In Controler js
#track cardTitle = 'Student details';
#track totalCount = 0; //This will be set by the apex controller later and will have dynamic number
When I try below code
<lightning-card title={cardTitle}{totalCount}></lightning-card>
It shows error as
multiple expressions found
.
No. You can only do it in controller JavaScript file.
I love part of the answer on SF stackexchange so I'm going to quote it here:
Your concerns about separating UI from controller logic do not apply
here as this is not a "controller". That MVC pattern is an Aura-ism.
This is the code which drives your component's functionality so it
makes sense that your JS would know about class names.
It's different but think about it that way - it'll let you write a proper unit test for the JavaScript. How you'd test logic that exists only in HTML layer? Or only in Visualforce page markup?
You can have only one expression. If you read documentation like https://developer.salesforce.com/docs/component-library/documentation/lwc/lwc.reference_directives
you'll see
The expression can be a JavaScript identifier (for example, person) or dot notation that accesses a property from an object (person.firstName). The engine doesn’t allow computed expressions (person2.name['John']). To compute the value of expression, use a getter in the JavaScript class.

Change href of Live Status link in Wagtail Admin

I made a one page scrolling site using wagtail. I have a homepage model and everything else is child pages such as about us, events, etc. On the admin page it creates a slug with the title of the child page which is what the live status link uses. For example it is <a href="/about-us/">. Is there a way to change the live status link at all?
The page URL is constructed by calling the get_url_parts method on the page model - by overriding this method, you can customise the resulting URL:
http://docs.wagtail.io/en/v1.13.1/reference/pages/model_reference.html#wagtail.wagtailcore.models.Page.get_url_parts
http://docs.wagtail.io/en/v1.13.1/topics/pages.html#customising-url-patterns-for-a-page-model
Normally, if you're overriding get_url_parts, you'd want to make a corresponding customisation to your site's URL routing behaviour, to ensure that the page is actually available at the URL in question; this can be done with RoutablePageMixin. In this case, though, it sounds like you're just using these subpages as placeholders for page content, and aren't bothered about them being accessible at their own URL - so you can get away with simply returning '/' as the page path:
class MyChildPage(Page):
# ...
def get_url_parts(self, *args, **kwargs):
url_parts = super(MyChildPage, self).get_url_parts(*args, **kwargs)
if url_parts is None:
# in this case, the page doesn't have a well-defined URL in the first place -
# for example, it's been created at the top level of the page tree
# and hasn't been associated with a site record
return None
site_id, root_url, page_path = url_parts
# return '/' in place of the real page path
return (site_id, root_url, '/')
I ran into this question when using Wagtail as a headless CMS for a Gatsby site. As I do use the URLs generated by Wagtail to structure the Gatsby site, redefining the get_url_parts method does not help me. I do want to keep the page URL as is and use a different host when clicking on the "View Live" or "Live" button in the admin.
I found that overriding the serve() method of the pages that you want to be served by a different host allows you to do just that.
from django.shortcuts import redirect
class BlogPage(Page):
...
def serve(self, request):
site_id, site_root, relative_page_url = self.get_url_parts(request)
return redirect('http://localhost:8001' + relative_page_url)
In the code above, the serve method of the BlogPage model is overridden to use the request and the get_url_parts method to extract the requested relative_page_url (that is relative to the site root -- in development that would be http://localhost). Since my frontend keeps the same URL structure as the Wagtail site, I just use the extracted relative_page_url and combine it with the host of the frontend (in this development case localhost:8001) and return a redirect response (generated with django.shortcuts.redirect) to that full URL.
It probably makes sense to turn this override into a mixin and a setting, so it does not have to be defined on every page model and the redirect host can be differentiated between environments.
You could also use the same logic of overriding the serve() method to redirect to any other location you may choose.

Use Angular's $location to get URL parameters from URL string instead of current URL

Can I (re)use Angular's $location or another Angular module to get URL parameters from a url? Or do I need to add (yet) another separate JS package to do this?
I have a URL string which I want to get the URL parameters from (aka searchstring). I know there's logic to do this in Angular.js, because $location has the search method. This returns the url parameters part as an object. For instance for a url https://www.domain.org/cool?minPrice=40&maxPrice=50 I can get the maxPrice value using: $location.search().maxPrice.
But this works only for the current url in the browser bar. I'm setting up an ngMock function that has to get url params from a URL passed in as a string parameter. I DON'T want a DIY solution as there is so much debate about what is correct, performant, etc due to things you might not think of it at first like:
- bad performance of regexp
- needing to url encode parameters
- order dependence, etc.
So I'd love to get this gift-wrapped. And ideally as an included-in-Angular solution so there's also no work for wrapping things up in an Angular service :P.
Note: If it's not possible I'll probably use uri.js, which I used to satisfaction in a non-Angular project a while ago.

Difference between AngularJS UI Router params object specified in state and views

I have just started working on AngularJS and specifically Angular UI Router project. While working on a project I observed that some of team members have specified params option object in view option object of state. when this is the case it doesn't accept optional parameters when passed through ui-sref/state.go.
However I moved this params option object to state instead of view and optional parameters feature started working. I am using AngularJS 1.3.x and AngularJS UI Router version 0.2.13. Here is the sample code to explain more clearly what I want to say :
$stateProvider.state('contacts', {
url:"/user/{userId}/contact"
views: {
'view1': {
....//other options
params :{userId:0,contactId:null}
}
}
...//other options including `controller` and `resolve` options.
});
In above sample code(I have given minimal required information) params object is specified on view1 object instead of on contacts state. Also contactId is the optional non-URL parameter which is passed on one of the use case and not passed in another one. However when I check $stateParams object in the controller specified on state it just shows up userId and not contactId even if I pass it.
I fixed this issue when I moved params option object from view1 object to contacts state object as shown below:
$stateProvider.state('contacts', {
url:"/user/{userId}/contact"
views: {
'view1': {
....//other options
//i have removed the `params` object from here..
}
}
...//other options including `controller` and `resolve` options.
params :{userId:0,contactId:null} //and have put it here.
});
Now I have following questions :
1) What difference does it make by changing where I specify params object. What are the significance if any?
2)Is specifying params object on view altogether wrong configuration? If yes then why UI router doesn't complain and works with parameters specified in URL?
If no then why it doesn't work with optional non-URL parameters?
3) Any specific use cases one would prefer specifying params option object on view object than on state object?
Also another side effect I found when I moved this params option object to state from view object is I am no longer able to bookmark this url or even refresh url in browser. When I do this it redirects me to our home page. Maybe this could be how we are handling this redirection in our project. But just curious to have any pointers why this could be happening?(including how generally this redirection is handled using ui-router) Of course I am going dig deep into our project code to see why this side-effect is happening.
However I would at least like to have answers to my 3 questions(and subquestions) I have asked here.
Neither the guide nor the API documentation say that a named view can have parameters. So I think adding params in the view was just a mistake, and it had no effect whatsoever.
So,
1) What difference does it make by changing where I specify params object. What are the significance if any?
In the views, ui-router doesn't care about it. In the state, it does what is documented in the API documentation.
2) Is specifying params object on view altogether wrong configuration? If yes then why UI router doesn't complain and works with parameters specified in URL? If no then why it doesn't work with optional non-URL parameters?
Yes, it seems to be wrong configuration.
3) Any specific use cases one would prefer specifying params option object on view object than on state object?
No

AngularJS - Changing the URL used in $resource.query method

I'm using AngularJS to integrate with a REST service which has already been built.
The REST API uses the following form for queries:
http://the.site/person/search/smith%20male (this searches for people called smith who are male)
I'm aware that this form isn't the best and will be ultimately getting the API changed to use a URL parameter.
Currently I'm just defining a resource inside my controller:
$scope.Summary = $resource("http://the.site/person/search");
this.Summary.query({ terms : 'smith male' });
but that generates URL's of the form /person/Search?terms=smith%20male
Is there a way to modify or override the URL used? I'm more familiar with Backbone where I was able to provide a url() function in my which generated the correct form of URL.
$scope.Summary = $resource("http://the.site/person/search/:terms");
this.Summary.query({ terms : 'smith male' });

Resources