Skip to content

Commit

Permalink
Include additional query values when interpolating href
Browse files Browse the repository at this point in the history
  • Loading branch information
ijjk committed Sep 5, 2020
1 parent ae7ae0b commit f656dd8
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 8 deletions.
2 changes: 1 addition & 1 deletion packages/next/client/page-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ export default class PageLoader {

const isDynamic: boolean = isDynamicRoute(route)
const interpolatedRoute = isDynamic
? interpolateAs(hrefPathname, asPathname, query)
? interpolateAs(hrefPathname, asPathname, query).result
: ''

return isDynamic
Expand Down
37 changes: 32 additions & 5 deletions packages/next/next-server/lib/router/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,10 @@ export function interpolateAs(
query

interpolatedRoute = route
const params = Object.keys(dynamicGroups)

if (
!Object.keys(dynamicGroups).every((param) => {
!params.every((param) => {
let value = dynamicMatches[param] || ''
const { repeat, optional } = dynamicGroups[param]

Expand Down Expand Up @@ -129,7 +131,21 @@ export function interpolateAs(
// n.b. We ignore this error because we handle warning for this case in
// development in the `<Link>` component directly.
}
return interpolatedRoute
return {
params,
result: interpolatedRoute,
}
}

function omitParmsFromQuery(query: ParsedUrlQuery, params: string[]) {
const filteredQuery: ParsedUrlQuery = {}

Object.keys(query).forEach((key) => {
if (!params.includes(key)) {
filteredQuery[key] = query[key]
}
})
return filteredQuery
}

/**
Expand Down Expand Up @@ -157,11 +173,16 @@ export function resolveHref(
) {
const query = searchParamsToUrlQuery(finalUrl.searchParams)

interpolatedAs = interpolateAs(
const { result, params } = interpolateAs(
finalUrl.pathname,
finalUrl.pathname,
query
)
interpolatedAs = formatWithValidation({
pathname: result,
hash: finalUrl.hash,
query: omitParmsFromQuery(query, params),
})
}

// if the origin didn't change, it means we received a relative href
Expand Down Expand Up @@ -608,7 +629,7 @@ export default class Router implements BaseRouter {
resolvedAs = delBasePath(resolvedAs)

if (isDynamicRoute(route)) {
const { pathname: asPathname } = parseRelativeUrl(resolvedAs)
const { pathname: asPathname, ...parsedAs } = parseRelativeUrl(resolvedAs)
const routeRegex = getRouteRegex(route)
const routeMatch = getRouteMatcher(routeRegex)(asPathname)
if (!routeMatch) {
Expand All @@ -632,7 +653,13 @@ export default class Router implements BaseRouter {
)
}
} else if (route === asPathname) {
as = interpolateAs(route, asPathname, query)
const { result, params } = interpolateAs(route, asPathname, query)
as = formatWithValidation(
Object.assign({}, parsedAs, {
pathname: result,
query: omitParmsFromQuery(query, params),
})
)
} else {
// Merge params into `query`, overwriting any specified in search
Object.assign(query, routeMatch)
Expand Down
7 changes: 6 additions & 1 deletion test/integration/dynamic-routing/pages/[name]/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import { useRouter } from 'next/router'
const Page = () => {
const router = useRouter()
const { query } = router
return <p id="asdf">This is {query.name}</p>
return (
<>
<p id="asdf">This is {query.name}</p>
<p id="query">{JSON.stringify(query)}</p>
</>
)
}

Page.getInitialProps = () => ({})
Expand Down
11 changes: 11 additions & 0 deletions test/integration/dynamic-routing/pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,17 @@ const Page = () => {
<a id="view-post-1-interpolated">View post 1 (interpolated)</a>
</Link>
<br />
<Link
href={{
pathname: '/[name]',
query: { name: 'post-1', another: 'value' },
}}
>
<a id="view-post-1-interpolated-more-query">
View post 1 (interpolated additional query)
</a>
</Link>
<br />
<Link href="/[name]/comments" as="/post-1/comments">
<a id="view-post-1-comments">View post 1 comments</a>
</Link>
Expand Down
36 changes: 35 additions & 1 deletion test/integration/dynamic-routing/test/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,9 @@ function runTests(dev) {
.elementByCss('#view-post-1-interpolated')
.getAttribute('href')

expect(url.parse(href).pathname).toBe('/post-1')
const parsedHref = url.parse(href, true)
expect(parsedHref.pathname).toBe('/post-1')
expect(parsedHref.query).toEqual({})

await browser.elementByCss('#view-post-1-interpolated').click()
await browser.waitForElementByCss('#asdf')
Expand All @@ -167,6 +169,38 @@ function runTests(dev) {
}
})

it('should navigate to a dynamic page successfully interpolated with additional query values', async () => {
let browser
try {
browser = await webdriver(appPort, '/')
await browser.eval('window.beforeNav = 1')

const href = await browser
.elementByCss('#view-post-1-interpolated-more-query')
.getAttribute('href')

const parsedHref = url.parse(href, true)
expect(parsedHref.pathname).toBe('/post-1')
expect(parsedHref.query).toEqual({ another: 'value' })

await browser.elementByCss('#view-post-1-interpolated-more-query').click()
await browser.waitForElementByCss('#asdf')

expect(await browser.eval('window.beforeNav')).toBe(1)

const text = await browser.elementByCss('#asdf').text()
expect(text).toMatch(/this is.*?post-1/i)

const query = JSON.parse(await browser.elementByCss('#query').text())
expect(query).toEqual({
name: 'post-1',
another: 'value',
})
} finally {
if (browser) await browser.close()
}
})

it('should allow calling Router.push on mount successfully', async () => {
const browser = await webdriver(appPort, '/post-1/on-mount-redir')
try {
Expand Down

0 comments on commit f656dd8

Please sign in to comment.