In this article, we will look at a simple example that Elm
gives of handling the request to navigate between single content pages when the user clicks on any link in SPA. To implement this example, we will need to install an additional package
support.
1 2 3 4 |
cd Documents && cd learn-elm elm install elm/url elm reactor |
Navigation
The first is still the main
program with full architectural elements required as input parameters of Browser.application< /code>.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
<span class="token keyword">module</span> <span class="token constant">Main</span> <span class="token keyword">exposing</span> <span class="token punctuation">(</span><span class="token hvariable">main< /span><span class="token punctuation">)</span> <span class="token import-statement"><span class="token keyword">import</span> Browser <span class="token keyword">exposing</span> </span><span class="token punctuation">(</span><span class="token operator">..</span><span class="token punctuation">)</span> <span class="token import-statement"><span class="token keyword">import</span> Browser.Navigation <span class="token keyword">as</span> Navigation <span class="token keyword ">exposing</span> </span><span class="token punctuation">(</span><span class="token constant">Key</span><span class="token punctuation">)< /span> <span class="token import-statement"><span class="token keyword">import</span> Html <span class="token keyword">exposing</span> </span><span class="token punctuation">(</span><span class="token operator">..</span><span class="token punctuation">)</span> <span class="token import-statement"><span class="token keyword">import</span> Html.Attributes <span class="token keyword">as</span> Attributes <span class="token keyword ">exposing</span> </span><span class="token punctuation">(</span><span class="token operator">..</span><span class="token punctuation">) </span> <span class="token import-statement"><span class="token keyword">import</span> Url <span class="token keyword">exposing</span> </span><span class="token punctuation">(</span><span class="token operator">..</span><span class="token punctuation">)</span> <span class="token comment">-- main - - - - - - - - - - - - - - - - - - - - - - - - - -</span> <span class="token keyword">type</span> <span class="token keyword">alias</span> <span class="token constant">SPA</span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token hvariable">init</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token constant">Url</span> <span class="token operator">-></span> <span class="token constant">Key</span> <span class="token operator">-></span> <span class="token punctuation">(</span> <span class="token constant">Model</span><span class="token punctuation">,</span> <span class="token constant">Cmd</ span> <span class="token constant">Msg</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token hvariable">view</span> <span class="token operator">:</span> <span class="token constant">Model</span> <span class="token operator">-></span> <span class="token constant">Document</span> <span class="token constant">Msg</span> <span class="token punctuation">,</span> <span class="token hvariable">update</span> <span class="token operator">:</span> <span class="token constant">Msg</span> <span class="token operator">-></span> <span class="token constant">Model</span> <span class="token operator">-></ span> <span class="token punctuation">(</span> <span class="token constant">Model</span><span class="token punctuation">,</span> <span class="token">Cmd</span> <span class="token constant">Msg</span> <span class="token punctuation">)</span> <span class="token punctuation">,</span> <span class="token hvariable">subscriptions</span> <span class="token operator">:</span> <span class="token constant">Model</span> <span class="token operator">-></span> <span class="token constant">Sub</span> <span class="token constant">Msg</span> <span class="token punctuation">,</span> <span class="token hvariable">onUrlRequest</span> <span class="token operator">:</span> <span class="token constant">UrlRequest</span> <span class="token operator">-></span> <span class="token constant">Msg</span> <span class="token punctuation">,</span> <span class="token hvariable">onUrlChange</span> <span class="token operator">:</span> <span class="token constant">Url</span> <span class="token operator">-></span> <span class="token constant">Msg</span> <span class="token punctuation">}</span> <span class="token hvariable">main</span> <span class="token operator">:</span> <span class="token constant">Program</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token constant">Model</span> <span class="token constant">Msg</span> <span class="token hvariable">main</span> <span class="token operator">=</span> <span class="token hvariable">Browser.application</span> <span class="token punctuation">(</span> <span class="token constant">SPA</span> <span class="token hvariable">init</span> <span class="token hvariable">view</span> <span class="token hvariable">update</span> <span class="token hvariable">subscriptions</span> <span class="token hvariable">onUrlRequest</span> <span class="token hvariable">onUrlChange</span> <span class="token punctuation">)</span> </span></span></span></span> |
We’ll have a very simple HTML architecture consisting of a list of <ul>
navigation links and a <div>
displays the content of the single page associated with each link. The content displayed here will simply be the full path of the single page to be displayed. Therefore, init
and view
should also be quite simple.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<span class="token comment">-- init - - - - - - - - - - - - - - - - - - - - - - - - - -</span> <span class="token keyword">type</span> <span class="token keyword">alias</span> <span class="token constant">Model</span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token hvariable">key</span> <span class="token operator">:</span> <span class="token constant">Key</span> <span class="token punctuation">,</span> <span class="token hvariable">url</span> <span class="token operator">:</span> <span class="token constant">Url</span> <span class="token punctuation">}</span> <span class="token hvariable">init</span> <span class="token operator">:</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token constant">Url</span> <span class="token operator">-></ span> <span class="token constant">Key</span> <span class="token operator">-></span> <span class="token punctuation">(</span> <span class="token constant">Model</span><span class="token punctuation">,</span> <span class="token constant">Cmd</span> <span class="token constant">Msg</ span> <span class="token punctuation">)</span> <span class="token hvariable">init</span> _ <span class="token hvariable">url</span> <span class="token hvariable">key</span> <span class="token operator ">=</span> <span class="token punctuation">(</span> <span class="token constant">Model</span> <span class="token hvariable">key</span> < span class="token hvariable">url</span><span class="token punctuation">,</span> <span class="token hvariable">Cmd.none</span> <span class="token punctuation">)</span> <span class="token comment">-- view - - - - - - - - - - - - - - - - - - - - - - - - - -</span> <span class="token hvariable">view</span> <span class="token operator">:</span> <span class="token constant">Model</span> <span class="token operator">-></span> <span class="token constant">Document</span> <span class="token constant">Msg</span> <span class="token hvariable">view</span> <span class="token hvariable">model</span> <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token hvariable">title</span> <span class="token operator">=</span> <span class="token string">"URL & Navigation"</span> <span class="token punctuation">,</span> <span class="token hvariable">body</span> <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token hvariable">ul</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">[</span> <span class="token hvariable">li</span> <span class="token punctuation">[</span><span class="token punctuation">] </span> <span class="token punctuation">[</span> <span class="token hvariable">link</span> <span class="token string">"/home"</span> < span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token hvariable">li</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">[</span> <span class="token hvariable">link</span> <span class="token string">"/profile"</span > <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token hvariable">li</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">[</span> <span class="token hvariable">link</span> <span class="token string">"/reviews/the-century -of-the-self"</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token hvariable">li</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">[</span> <span class="token hvariable">link</span> <span class="token string">"/reviews/public-opinion "</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token hvariable">li</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">[</span> <span class="token hvariable">link</span> <span class="token string">"/reviews/shah-of -shahs"</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token punctuation">,</span> <span class="token hvariable">div</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">[</span> <span class="token hvariable">h1</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">[</span> <span class="token hvariable">text</span> <span class="token punctuation">( </span> <span class="token constant">Url</span><span class="token punctuation">.</span><span class="token builtin">toString</span> <span class="token hvariable">model</span><span class="token punctuation">.</span><span class="token hvariable">url</span> <span class="token punctuation">)</ span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token punctuation">]</span> <span class="token punctuation">}</span> <span class="token hvariable">link</span> <span class="token operator">:</span> <span class="token constant">String</span> <span class="token operator">-></span> <span class="token constant">Html</span> <span class="token hvariable">msg</span> <span class="token hvariable">link</span> <span class="token hvariable">path</span> <span class="token operator">=</span> <span class="token hvariable">a</span> <span class="token punctuation">[</span> <span class="token hvariable">href</span> <span class="token hvariable">path</span> <span class="token punctuation">]</span> <span class="token punctuation">[</span> <span class="token hvariable">text</span> <span class="token hvariable">path </span> <span class="token punctuation">]</span> </span></span> |
Here neither init
and view
have no point sending Msg</ code> to the main controller
Program
. However, there is a new element that is the Key
style used at init
. This value is used to ensure that the sub-program
of module Navigation
includes pushUrl
, replaceUrl
, back
, and forward
will indicate valid if supplied correctly key
initialized when the new web page was downloaded to the browser.
The cases handled at update
will now include:
- User enters a new address in the
Address Bar
address bar of the web browser. - User clicks on a link in the web page:
- Link to a single site in the same system
- Link pointing to another website
1 2 3 4 5 6 7 8 9 10 11 12 |
<span class="token comment">-- update - - - - - - - - - - - - - - - - - - - - - - - - - -</span> <span class="token keyword">type</span> <span class="token constant">Msg</span> <span class="token operator">=</span> <span class="token constant">LinkClicked</span> <span class="token constant">UrlRequest</span> <span class="token operator">|</span> <span class="token constant">UrlChanged</span> <span class="token constant">Url</span> <span class="token hvariable">update</span> <span class="token operator">:</span> <span class="token constant">Msg</span> <span class="token operator">-></span> <span class="token constant">Model</span> <span class="token operator">-></span> <span class="token punctuation">(</ span> <span class="token constant">Model</span><span class="token punctuation">,</span> <span class="token constant">Cmd</span> <span class="token constant">Msg</span> <span class="token punctuation">)</span> <span class="token hvariable">update</span> <span class="token hvariable">msg</span> <span class="token hvariable">model</span> <span class="token operator">=</span> <span class="token keyword">case</span> <span class="token hvariable">msg</span> <span class="token keyword">of</span> <span class="token constant">UrlChanged</span> <span class="token hvariable">newURL</span> <span class="token operator">-></span> <span class="token">(</span> <span class="token punctuation">{</span> <span class="token hvariable">model</span> <span class="token operator">|</span> <span class="token hvariable">url</span> <span class="token operator">=</span> <span class="token hvariable">newURL</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token hvariable">Cmd.none</span> <span class="token punctuation">)</span> <span class="token constant">LinkClicked</span> <span class="token hvariable">urlRequest</span> <span class="token operator">-></span> <span class="token keyword">case</span> <span class="token hvariable">urlRequest</span> <span class="token keyword">of</span> <span class="token constant">Browser.Internal</span> <span class="token hvariable">url</span> <span class="token operator">-></span> <span class="token punctuation">(</span> <span class="token hvariable">model</span><span class="token punctuation">,</span> <span class="token hvariable">Navigation.pushUrl </span> <span class="token hvariable">model</span><span class="token punctuation">.</span><span class="token hvariable">key</span> <span class="token punctuation">(</span> <span class="token constant">Url</span><span class="token punctuation">.</span><span class="token builtin">toString</ span> <span class="token hvariable">url</span> <span class="token punctuation">)</span> <span class="token punctuation">)</span> <span class="token constant">Browser.External</span> <span class="token hvariable">href</span> <span class="token operator">-></span> <span class="token punctuation">(</span> <span class="token hvariable">model</span><span class="token punctuation">,</span> <span class="token hvariable">Navigation.load </span> <span class="token hvariable">href</span> <span class="token punctuation">)</span> </span></span> |
And the rest of the architectural elements…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<span class="token comment">-- subscriptions - - - - - - - - - - - - - - - - - - - - - - - - - -</span> <span class="token hvariable">subscriptions</span> <span class="token operator">:</span> <span class="token constant">Model</span> <span class="token operator">-></span> <span class="token constant">Sub</span> <span class="token constant">Msg</span> <span class="token hvariable">subscriptions</span> _ <span class="token operator">=</span> <span class="token hvariable">Sub.none</span> <span class="token comment">-- onUrlRequest - - - - - - - - - - - - - - - - - - - - - - - - - -</span> <span class="token hvariable">onUrlRequest</span> <span class="token operator">:</span> <span class="token constant">UrlRequest</span> <span class="token operator">-></span> <span class="token constant">Msg</span> <span class="token hvariable">onUrlRequest</span> <span class="token operator">=</span> <span class="token constant">LinkClicked</span> <span class="token comment">-- onUrlChange - - - - - - - - - - - - - - - - - - - - - - - - - -</span> <span class="token hvariable">onUrlChange</span> <span class="token operator">:</span> <span class="token constant">Url</span> <span class="token operator">-></span> <span class="token constant">Msg</span> <span class="token hvariable">onUrlChange</span> <span class="token operator">=</span> <span class="token constant">UrlChanged</span> |
SPA’s navigation logic is pretty easy to follow now with onUrlChange
and onUrlRequest
. Because after all, when the association changes, we only have these possibilities:
- Or user enters a new address in
address bar
, thenonUrlChange
will be fired andUrlChanged
is sent toupdate
. - Or the user clicks on a link in the web page,
onUrlRequest
will be fired andLinkClicked
will be activated. send toupdate
.
http://localhost:8000/src/ Main.elm
Only case where update
needs to generate Model
records with url The new
is when a user clicks on a link that points to a single page of content in the same system. That’s when the new Model
record is sent to view
and we will have the look and feel of our website changed to the new interface. single page appearance that meets the requirements.
And of course, in this case the web browser won’t need to reload the entire HTML text and the user won’t have to temporarily see a blank window.
URL Parser
In fact, after basic navigation, we will have to learn more about how to parse the request path Request Url
in the case of a user click on a link that points to a single page in the same system.
However, learning the tools to handle this task group will require the use of sub-program
called Higher Order Functions
that I have determined is for the next Sub-Series. And so our SPA story will need to go back a bit until Higher Order Functions
and some related concepts are finished in the new Sub-Series :
(unpublished) [Functional Programming + Elm/Haskell] Lesson 1 – …
In parallel, the Sub-Series Declarative
will still be continued as a small project
building a SPA using the Back-End is Wikipedia API.
(not published) [Declarative Programming + Elm] Lesson 16 – …