I have a page with links. These links all end in the same way. For example www.site.com/fruit/apples, www.site.com/fruit/bananas, www.site.com/fruit/oranges, etc. I want all these links to call the same Dart app and have the app do some processing and then redirect you wherever you need to go (the bananas page vs. the oranges page). This way, I avoid having an actual HTML file for every single fruit. I can instead have a single landing template that gets populated with variable fruit data.
The part I'm hung up on is passing the url into the Dart app so it can do the handling. I understand main() cannot receive arguments, so what's another way?
You can use the route package to handle the URL's for you.
For example:
import 'package:route/client.dart';
final fruitUrl = new UrlPattern(r'/fruit/(\w+)');
main() {
var router = new Router()
..addHandler(fruitUrl, showFruit)
..listen();
}
void showFruit(String path) {
var fruit = fruitUrl.parse(req.path)[0];
// Display the page according to the fruit type
}
If you don't need to handle actual routes, and you just want to handle any query parameters passed of the form ?fruit=apple you don't have to use the routes package and can instead manually parse the URL:
Map params = {};
// If arguments were provided, decode them into params map
if(window.location.search.length > 1) {
// Break all arguments into form: fruit=apple
List<String> queryPairs = window.location.search.substring(1).split('&');
for(String queryPair in queryPairs) {
// Add arguments into params map: key=fruit, value=apple
List<String> queryPairList = queryPair.split('=');
params[queryPairList[0]] = queryPairList[1];
}
}
// Handle the proper action based on the fruit
switch(params['fruit']) {
case 'apple':
// ...
break;
// ...
case 'orange':
// ...
break;
}
Related
I have the following URL on my webpage upon pagination
http://localhost:9000/employee?p=2
I need to prompt to not found page whenever the parameter "p" is change. example:
http://localhost:9000/employee?b=2
It need the controller to input a notFound. what kind of condition will i do to do this?
Reference:
Controller:
#Transactional(readOnly=true)
public static Result list(int pageNum, int listSize) {
employeeMap.clear();
Page page = appModel.page(pageNum, listSize);
employeeMap = ListUtil.getEmpMap(employeeMap, page.getEmpList());
AppModel employees = new AppModel(employeeMap, searchMap);
/* if statement initiate a notFound page if pageNum us not the expected value */
if (pageNum < 0 || pageNum > page.getPage().get("intLastPage")) {
return notFound("<h1>Page not found</h1>").as("text/html");
}
/* if statement that put a not search found message if no employee is found */
if (page.getEmpList().size() == 0) {
flash("success", "There is no search results for the specified conditions");
}
return ok(index.render(appModelForm.fill(employees),page));
}
Routes:
# Employee list (look at the default values for pagination parameters)
GET /employee controllers.Application.list(p:Int ?= 1,l:Int ?= 125)
You could prevent people from switching that name of the parameter overall by changing your routing. But to achieve all the possibilities outlined by what you want to do, you could do the following:
GET /employee/:p/:l controllers.Application.list(p:Int ?= 1,l:Int ?= 125)
GET /employee/p/:p controllers.Application.list(p:Int, 125)
GET /employee/l/:l controllers.Application.list(1, l:Int)
It depends on how you handle the URL calling in the template, but if you can have that auto-generate the default parameters into the URL if the user does not put them in, you could just keep the first one by itself.
The URL to summon your controller will now instead be:
http://localhost:9000/employee/p/2
http://localhost:9000/employee/l/4
http://localhost:9000/employee/2/4
And then you can route anything else to a not found controller method:
GET /employee/--String, empty or whatever else--- controllers.Application.returnNotFound
#Transactional(readOnly=true)
public static Result returnNotFound() {
return notFound("<h1>Page not found</h1>").as("text/html");
}
In Vapor, specifically in the class for a custom Leaf tag, how can you retrieve values stored in a context?
I'm trying to implement a tag that takes a string and a path, and renders a link unless the path is the current page, so, for example, #navElement("About Us", "/about") will produce a link to the site's about page on every page except the about page itself. On that page, it should display the text without a link on it.
I don't want to have to pass the current path to the tag every time I use it, so I've stored the request's path in the context, roughly like this (checks omitted):
drop.get(":page"){ request in
return try drop.view.make(thePage, ["path": request.uri.path])
}
I can use #(path) in a template and see the path I expect.
My custom tag is derived from Tag, and its run method receives the context as an argument, and I can see the stored value in there in the debugger – but how do I get at it? The get method in the Context class, which seems to do this, is internal, so I can't use it. There is a comment that says subscripts are to be done, and I assume that this will ultimately be the way to extract values from the context, but in the meantime, is there any way to retrieve them?
Just make the current path one of the arguments to your tag.
Droplet route:
drop.get(":page") { request in
return try drop.view.make(thePage, ["currentPath": request.uri.path])
}
In template:
#navElement("About Us", "/about", currentPath)
Tag:
class NavElement: Tag {
let name = "navElement"
public func run(stem: Stem, context: LeafContext, tagTemplate: TagTemplate, arguments: [Argument]) throws -> Node? {
guard
let linkText = arguments[0].value?.string,
let linkPath = arguments[1].value?.string,
let currentPath = arguments[2].value?.string
else { return nil }
if linkPath == currentPath {
return Node("We are at \(currentPath)")
} else {
return Node("Link \(linkText) to \(linkPath)")
}
}
}
Edit:
I have spoken to the developers of Vapor, and they do not intend to open up access to Context's contents publicly. However, since the queue: List<Node>() is public, you can just copy the get() function into your own extension and then you'll be able to do as you wanted.
I want to know how I can access the parsed model of my program. I have a validation check written in xtend which accepts a rule A as it parameter. however I want to search the entire parsed tree and make sure that any other reference to this specific instance of A follows certain specifications.
#Check
def checkActionBelongsToAssociatedRole(ActionDsc act){
var pRole = act.parentRole
var rs = new ResourceSetImpl()
//DONT KNOW IF THIS IS RIGHT
var resource = rs.getResource(URI.createURI("./model/generated/Protocol.ecore"), true)
for(r:resource.allContents.toIterable.filter(typeof(RoleDec))){
if(r.name == pRole.name){
//DO SOMETHING
}
}
}
In the generator file that I have I already get the Resource object as a parameter.
override void doGenerate(Resource resource, IFileSystemAccess fsa) {
//Generate code
}
How can I do the same thing for my validator. Thank you in advance!
act.eResource() allows to access the resource that contains the action.
Doing some investigation for using dust.js, and I was wondering is there a way from preventing bad data to be rendered.
Template
Hello {name}! You have {count} new messages
Context
{
"name": "Mick",
"count": Math.PI
}
Yields, this result:
Hello Mick! You have 3.141592653589793 new messages
In this example, is there a way to escape the Math.PI, so that we can bail out and not print 3.14..
You, as the developer, have to decide what is 'bad data' and what is an acceptable alternative.
Then you must either transform it in code (eg. the node.js building the page) before it reaches dust.js, or write a helper to render whatever you want with appropriate fallback. For instance, if you want to render integers, and display some custom fallback text otherwise, you might use a helper something like this:
Create an integerOrElse function, and save it in a file, eg.
local-dust-helpers.js:
// this extends dustjs-helpers (which must therefore be in package.json)
var dust = require('dustjs-helpers');
dust.helpers.integerOrElse = function (chunk, ctx, bodies, params) {
// tap function resolves variables in params
var value = dust.helpers.tap(params.value, chunk, ctx),
fallback = dust.helpers.tap(params.fallback, chunk, ctx) || '';
// define a fallback for the fallback :) ----------------^^^^^
// for more brevity, you could do this in one line with a ternary operator
if (!isNaN(value) && parseInt(value) == value) {
return chunk.write(value);
} else {
return chunk.write(fallback);
}
}
Then require() it in your app, replacing where you would have called the vanilla dust.js:
app.js
...
var dust = require('./local-dust-helpers');
...
You can then use it just like a native dust.js directive:
template.dust
Hello {name}!
You have {#integerOrElse value='{count}' fallback='some' /} new messages
CakePHP URL query parameters are not done in a standard fashion e.g. the params are /param1:value1/param2:value2 instead of ?param1=value1¶m2=value2
This means that the javascript location.search does not return a value.
There is a getQueryParams JQuery plugin that does what I want using location.search
I have had to modify this to use
var pairs = location.pathname.split('/');
instead of
var pairs = location.search.substring(1).split('&');
However this now includes everything except the host in the variable pairs. So I have to check for a ':' to see if it is a parameter.
This works - but is there a better (more Cake like) way of doing it? I don't want to improve on the JQuery plugin (e.g. Regex), I want to find a better way to integrate the plugin with CakePHP.
Upddate: I've removed the rest of the JQuery code as I'm happy with the jquery code, my issue is with fitting it more with cake
Is there some 'Cake like' way of removing the path to your app, the model and the controller from location.pathname so that you end up what you would normally get from location.search?
Since you're searching for a particular parameter, you can use a regular expression:
$.getQueryParam = function (param) {
var re = new RegExp(param+':([^\/]+)');
var matches = location.pathname.match(re);
if (matches.length) {
return matches[1];
}
return undefined;
}
So it appears there isn't a better way of doing it. Here is the javascript for reference:
// jQuery getQueryParam Plugin 1.0.1 (20100429)
// By John Terenzio | http://plugins.jquery.com/project/getqueryparam | MIT License
// Modified by ICC to work with cakephp
(function ($) {
// jQuery method, this will work like PHP's $_GET[]
$.getQueryParam = function (param) {
// get the pairs of params fist
// we can't use the javascript 'location.search' because the cakephp URL doesn't use standard URL params
// e.g. the params are /param1:value1/param2:value2 instead of ?param1=value1¶m2=value2
var pairs = location.pathname.split('/');
// now iterate each pair
for (var i = 0; i < pairs.length; i++) {
// cakephp query params all contain ':'
if (pairs[i].indexOf(':') > 0) {
var params = pairs[i].split(':');
if (params[0] == param) {
// if the param doesn't have a value, like ?photos&videos, then return an empty srting
return params[1] || '';
}
}
}
//otherwise return undefined to signify that the param does not exist
return undefined;
};
})(jQuery);