mirror of
https://github.com/aspnet/JavaScriptServices.git
synced 2025-12-24 02:30:13 +00:00
Make templates work with nonempty baseUrls (e.g., IIS virtual directories)
This commit is contained in:
@@ -4,12 +4,14 @@ import * as ko from 'knockout';
|
||||
import './webpack-component-loader';
|
||||
import AppRootComponent from './components/app-root/app-root';
|
||||
const createHistory = require('history').createBrowserHistory;
|
||||
const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href');
|
||||
const basename = baseUrl.substring(0, baseUrl.length - 1); // History component needs no trailing slash
|
||||
|
||||
// Load and register the <app-root> component
|
||||
ko.components.register('app-root', AppRootComponent);
|
||||
|
||||
// Tell Knockout to start up an instance of your application
|
||||
ko.applyBindings({ history: createHistory() });
|
||||
ko.applyBindings({ history: createHistory({ basename }), basename });
|
||||
|
||||
// Basic hot reloading support. Automatically reloads and restarts the Knockout app each time
|
||||
// you modify source files. This will not preserve any application state other than the URL.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<div class='container-fluid'>
|
||||
<div class='row'>
|
||||
<div class='col-sm-3'>
|
||||
<nav-menu params='route: route'></nav-menu>
|
||||
<nav-menu params='router: router'></nav-menu>
|
||||
</div>
|
||||
<div class='col-sm-9' data-bind='component: { name: route().page, params: route }'></div>
|
||||
</div>
|
||||
|
||||
@@ -12,12 +12,12 @@ const routes: Route[] = [
|
||||
|
||||
class AppRootViewModel {
|
||||
public route: KnockoutObservable<Route>;
|
||||
private _router: Router;
|
||||
public router: Router;
|
||||
|
||||
constructor(params: { history: History.History }) {
|
||||
constructor(params: { history: History.History, basename: string }) {
|
||||
// Activate the client-side router
|
||||
this._router = new Router(params.history, routes)
|
||||
this.route = this._router.currentRoute;
|
||||
this.router = new Router(params.history, routes, params.basename);
|
||||
this.route = this.router.currentRoute;
|
||||
|
||||
// Load and register all the KO components needed to handle the routes
|
||||
// The optional 'bundle-loader?lazy!' prefix is a Webpack feature that causes the referenced modules
|
||||
@@ -32,7 +32,7 @@ class AppRootViewModel {
|
||||
// To support hot module replacement, this method unregisters the router and KO components.
|
||||
// In production scenarios where hot module replacement is disabled, this would not be invoked.
|
||||
public dispose() {
|
||||
this._router.dispose();
|
||||
this.router.dispose();
|
||||
|
||||
// TODO: Need a better API for this
|
||||
Object.getOwnPropertyNames((<any>ko).components._allRegisteredComponents).forEach(componentName => {
|
||||
|
||||
@@ -12,7 +12,7 @@ class FetchDataViewModel {
|
||||
public forecasts = ko.observableArray<WeatherForecast>();
|
||||
|
||||
constructor() {
|
||||
fetch('/api/SampleData/WeatherForecasts')
|
||||
fetch('api/SampleData/WeatherForecasts')
|
||||
.then(response => response.json() as Promise<WeatherForecast[]>)
|
||||
.then(data => {
|
||||
this.forecasts(data);
|
||||
|
||||
@@ -13,17 +13,17 @@
|
||||
<div class='navbar-collapse collapse'>
|
||||
<ul class='nav navbar-nav'>
|
||||
<li>
|
||||
<a href='/' data-bind='css: { active: route().page === "home-page" }'>
|
||||
<a data-bind='attr: { href: router.link("/") }, css: { active: route().page === "home-page" }'>
|
||||
<span class='glyphicon glyphicon-home'></span> Home
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='/counter' data-bind='css: { active: route().page === "counter-example" }'>
|
||||
<a data-bind='attr: { href: router.link("/counter") }, css: { active: route().page === "counter-example" }'>
|
||||
<span class='glyphicon glyphicon-education'></span> Counter
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href='/fetch-data' data-bind='css: { active: route().page === "fetch-data" }'>
|
||||
<a data-bind='attr: { href: router.link("/fetch-data") }, css: { active: route().page === "fetch-data" }'>
|
||||
<span class='glyphicon glyphicon-th-list'></span> Fetch data
|
||||
</a>
|
||||
</li>
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
import * as ko from 'knockout';
|
||||
import { Route } from '../../router';
|
||||
import { Route, Router } from '../../router';
|
||||
|
||||
interface NavMenuParams {
|
||||
route: KnockoutObservable<Route>;
|
||||
router: Router;
|
||||
}
|
||||
|
||||
class NavMenuViewModel {
|
||||
public router: Router;
|
||||
public route: KnockoutObservable<Route>;
|
||||
|
||||
constructor(params: NavMenuParams) {
|
||||
// This viewmodel doesn't do anything except pass through the 'route' parameter to the view.
|
||||
// You could remove this viewmodel entirely, and define 'nav-menu' as a template-only component.
|
||||
// But in most apps, you'll want some viewmodel logic to determine what navigation options appear.
|
||||
this.route = params.route;
|
||||
this.router = params.router;
|
||||
this.route = this.router.currentRoute;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ export class Router {
|
||||
private disposeHistory: () => void;
|
||||
private clickEventListener: EventListener;
|
||||
|
||||
constructor(history: History.History, routes: Route[]) {
|
||||
constructor(private history: History.History, routes: Route[], basename: string) {
|
||||
// Reset and configure Crossroads so it matches routes and updates this.currentRoute
|
||||
crossroads.removeAllRoutes();
|
||||
crossroads.resetState();
|
||||
@@ -33,8 +33,9 @@ export class Router {
|
||||
let target: any = evt.currentTarget;
|
||||
if (target && target.tagName === 'A') {
|
||||
let href = target.getAttribute('href');
|
||||
if (href && href.charAt(0) == '/') {
|
||||
history.push(href);
|
||||
if (href && href.indexOf(basename + '/') === 0) {
|
||||
const hrefAfterBasename = href.substring(basename.length);
|
||||
history.push(hrefAfterBasename);
|
||||
evt.preventDefault();
|
||||
}
|
||||
}
|
||||
@@ -46,6 +47,10 @@ export class Router {
|
||||
crossroads.parse((history as any).location.pathname);
|
||||
}
|
||||
|
||||
public link(url: string): string {
|
||||
return this.history.createHref({ pathname: url });
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
this.disposeHistory();
|
||||
$(document).off('click', 'a', this.clickEventListener);
|
||||
|
||||
Reference in New Issue
Block a user