I'm trying to see if there is a way to do areas in Durandaljs
Something along the lines of
/App/areas/home
/views
/viewmodels
/other
/views
/viewmodels
I see the viewLocator allowing this convention:
viewLocator.useConvention('viewmodels', 'views', 'areas');
but the router.useConvention() seems to default to same path.
Is there a proper way to account for this, the documentation is light in this regard.
yes you can do this.
Since you are using Durandal.router you can use a convention of where to find your ViewModels by overriding the routers autoConvertRouteToModuleId like so:
router.autoConvertRouteToModuleId = function(url, params) {
return url + '/' + 'params[0]';
};
As for finding the view that binds to your viewmodel then you can like you have above.. change the viewlocator convention.
Related
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
}
});
My URLs have double colon on them.
I push a path to Nuxt router which has : as a part of it.
export default {
router: {
extendRoutes (routes, resolve) {
routes.push({
name: 'custom',
path: 'towns' + '(:[0-9].*)?/',
component: resolve(__dirname, 'pages/404.vue')
})
}
}
}
When I point to http://localhost:3000/towns:3 , for example, the : is translated as %3Aon the URL leading to this error message:
Expected "1" to match ":[0-9].*", but received "%3A2"
How to revert this to : ?
I tried encodeURI(), decodeURI(), encodeURIComponent() and decodeURIComponent() in vain.
A demo for the ones who wants to try: nuxt-extend-routes
Any suggestions are welcome
Vuex is using vue-router and vue-router is using path-to-regexp to parse router path configuration
It seems to me, that you are trying to use Unnamed Parameters which doesn't make sense because vue-router/vuex need the name of the parameter to pass it down to Vue component behind the route
Why don't just use named parameters ?
{
path: '/towns:id(:\\d+)',
name: 'Page 3',
component: Page3
}
Sure, result will be that $route.params.id value will be prefixed with : and all router-link params must be :XX instead of 'XX' but that's something you can deal with. vue-router (path-to-regexp) is using : to "mark" named path parameters ...there's no way around it
You can take a look at this sandbox. Its not Nuxt but I'm pretty sure it will work in Nuxt same way....
Update
Well it really doesn't work in Nuxt. It seems Nuxt is for some reason applying encodeURIComponent() on matched path segments and throws an error. It works when server-side rendering tho (it throws some error on client still)...
Firstly, I concur with Michal Levý's answer that there's a library bug here. The line throwing the error is here in the Nuxt source:
https://github.com/nuxt/nuxt.js/blob/112d836e6ebbf1bd0fbde3d7c006d4d88577aadf/packages/vue-app/template/utils.js#L523
You'll notice that a few lines up the segment is encoded, leading to : switching to %3A.
However, this line appears to have originated from path-to-regexp:
https://github.com/pillarjs/path-to-regexp/blob/v1.7.0/index.js#L212
It isn't trivial to fix this bug because the encoding is not simply 'wrong'. There's a lot of stuff going on here and by the time that line is reached the parameter values have been URL decoded from their original values. In the case of our unencoded : that causes problems but in other cases, such as matching %3A, the encoding would be required.
The handling of encoding within path-to-regexp is a delicate topic and we aren't helped by the old version being used. This also makes it more difficult to come up with a suitable workaround in your application.
So, let's see what we can do...
To start with, let's consider the path:
path: 'towns' + '(:[0-9].*)?/',
Bit odd to concatenate the strings like that, so I'm going to combine them:
path: 'towns(:[0-9].*)?/',
The / on the end isn't hurting but it seems to be unnecessary noise for the purposes of this question so I'm going to drop it.
On the flip side, not having a / at the start can cause major problems so I'm going to add one in.
The .* is suspicious too. Do you really mean match anything? e.g. The current route will match towns:3abcd. Is that really what you want? My suspicion is that you want to match just digits. e.g. towns:3214. For that I've used [0-9]+.
That leaves us with this:
path: '/towns(:[0-9]+)?',
Now, the : problem.
In general, route paths are used in both directions: to match/parse the URL and to build the URL. Your use of an unnamed parameter makes me wonder whether you only intend to use this route for matching purposes.
One option might be this:
path: '/towns:([0-9]+)',
By moving the : outside the parameter it dodges the encoding problem.
There are two problems with the code above:
The colon/number suffix is no longer optional on the URL. i.e. It won't match the path /towns as the original route did. This can be solved by registering /towns as a separate route. I'm not aware of any other way to solve this problem with the available version of path-to-regexp.
You won't be able to use it to build URLs, e.g. with nuxt-link.
If you need to be able to use it to build URLs too then you could use a named parameter instead:
path: '/towns::town([0-9]+)',
The :: part here is potentially confusing. The first : is treated literally whereas the second : is used as a prefix for the town parameter. You might then use that with nuxt-link like this:
<NuxtLink :to="{ name: 'custom', params: { town: 4 } }">
...
</NuxtLink>
I am using Nuxt to create my application and I have a group of pages that are related in a way.
So I will simplify things a bit but my current structure looks like this
/pages
/login
/registration
/forgot-password
/resend-confirmation-email
.
.
.
This folder structure is creating /login, /registration, /forgot-password, /resend-confirmation-email routes, which is cool.
So, in a way I can group first four pages to a group and name it authorization.
Ideally new folder structure should look like
/pages
/authorization
/login
/registration
/forgot-password
/resend-confirmation-email
.
.
.
However what I would like is for the router to not get messed up, I would very much like for those routes to remain the way they were.
Is that possible?
So with no plugins and stuff, what I did was replacing the folder name from route object in extend routes function.
File nuxt.config.js
router: {
extendRoutes(nuxtRoutes) {
nuxtRoutes.map(route => {
route.path = route.path.replace('/authorization', '');
route.name = route.name.replace('authorization-', '');
return route;
});
},
....
}
This looks like a hack to me, but it actually does exactly what I want. For some larger projects I might consider fully overriding the router but this is kinda okay for now.
You can use nuxt router extras module
https://github.com/alibaba-aero/nuxt-router-extras/blob/dev/README.md
<router>
path: /posts
</router>
I am developing a social networking website using Yii. While frequently using the following things I am having great data manageability issue.
- User ID
- Current user ID (the user which profile is the owner viewing)
- Is owner???
where can I define these things.
I would something like
if(Yii::app()->owner==ME){
//do something
}
// and similarly
if($this->isMyFreind(<Current user ID>){
}
// $this(CanIView()){
}
I want these functions to be public for any page? But how?
In other words
Where can I put my library which contains my own favorite functions like text shortening, image cropping, date time format etc etc??
In Yii, you can do achieve this by making a class (under protected/compoents) which inherits
CApplicationComponent
class. And then you call any property of this class globally as a component.
class GlobalDef extends CApplicationComponent {
public $aglobalvar;
}
Define this class in main config under components as:
'globaldef' => array('class' => 'application.components.GlobalDef '),
And you can call like this:
echo Yii::app()->globaldef->aglobalvar;
Hope that can help.
According to the MVC model, things like image cropping or date time formats would go in models. You would simply create models for that.
I usually use a globals.php file with all my common functions
In the index.php (yip the one in the root):
$globals='protected/globals.php';
require_once($globals);
I can then call my global functions anywhere. For example, I shorten certain Yii functions like:
function bu($url=null){
static $baseUrl;
if ($baseUrl===null)
$baseUrl=Yii::app()->request->baseUrl;
return $url===null ? $baseUrl : $baseUrl.'/'.ltrim($url,'/');
}
So I can then call the Yii::app()->request->baseUrl by simply calling bu()
I have an issue with CF9 ORM mapping.
I get the following error from time to time (yes, it works fine most of the time),
Mapping for component model.Pubs not found. Either the mapping for this component is missing or the application must be restarted to generate the mapping.
ORM definition in Application.cfc
<cfscript>
this.datasource = "Pubs";
this.ormenabled = true;
this.ormsettings= {
dialect="MicrosoftSQLServer",
dbcreate="update",
eventhandling="true"
};
</cfscript>
<cfset this.mappings["/model"] = getDirectoryFromPath(getCurrentTemplatePath()) & "model" />
The only way to fix it is to refresh the ORM couple of time, which is by hitting ?init=true on Application.cfc. It is still a temporary solution, but I need to know the root cause of it and fix it.
<cfscript>
if(structKeyExists(url, "init")) { ormReload(); applicationStop(); location('index.cfm?reloaded=true'); }
Please advise.
Thanks!
I also had your problem, but now it works fine. First, if you don't set ormsettings.cfclocation, ColdFusion does this:
If it is not set, ColdFusion looks at the application directory, its sub-directories, and its mapped directories to search for persistent CFCs. (see Spec)
This is error prone, because you never know what ColdFusion finds in all that directories.
When you add cfclocation to your example it should work:
this.ormsettings= {
cfclocation = ["/model", "/other/entities", "/more/other/entites"]
}
There is a lot of discussion out there, about how to specify the paths for cfclocation. For me, that way works.
But the first element of my cfclocation is always an application mapping, like your this.mappings["/model"]. I have not tested it with webserver aliases or CFCs in the webroot, without mapping. You should also avoid colliding namespaces, like a "model" directory in the webroot, while having a "/model" mapping.
Good luck:)
Okay, thank you both #Henry and #Walter for your comments. They were the lead toward the right solution.
Here's what I did to make sure it's stable ALL the time.
I used one folder (location) for all ORM CFCs. There used to be a "model" folder for each section. Sections are sibling folders under one root and share the same Application.cfc.
I changed that to ONE root level folder for all CFCs, ie: /root/ormmodel
On the /root/Application.cfc, I adjusted the following code
<cfset application.mappings["/ormmodel"] = expandPath("/root/ormmodel") />
and
this.ormsettings= {
cfclocation = ["ormmodel"],
autogenmap = true,
...
eventhandling="true"
};
Notice the missing "/" in the cfclocation value.
On calling for model components, I changed the code from pub = new ormmodel.Pubs() to
pub = EntityNew("Pubs");
On an unrelated point, I've changed my components name to camelCase naming and avoided special characters like underscores and dashes.
I hope this would be helpful and save someone else hours of frustration and suspense.
Happy coding!