3
\$\begingroup\$

I'm getting back into web development, and I'm creating a mobile-friendly web app. I'm trying to make it SPA-like in the sense that I don't load new pages for each action the user takes. As my index.cshtml page will show, I have a header, and then I have a bunch of divs. Those divs serve as placeholders for each "page" in the app. Only one div is shown at a time. Is this an acceptable approach? Is there a better way that's considered best practice?

Index.cshtml:

@model PrestoDashboardWeb.Models.EntityContainer
<!DOCTYPE html>
<html lang="en">
    <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">
    <link href="~/Content/jquery.mobile-1.3.2.min.css" rel="stylesheet" />    
    <script src="~/Scripts/jquery-1.8.2.min.js"></script>
    <script src="~/Scripts/jquery.mobile-1.3.2.min.js"></script>
    <title>Presto</title>

    </head>

    <body>

        <div data-role="header" data-theme="a">
            <img src="~/Content/images/wizard1.ico" height="48" width="48" style="display: block; float: right;"/>
            <h1 style="font-size: 32px">Presto</h1>
        </div>

        <div data-role="navbar" data-grid="d">
            <ul> <!-- These are the different actions the user can take. -->
                <li onclick="showApps()"><a href="#" class="ui-btn-active">Apps</a></li>
                <li onclick="showServers()"><a href="#">Servers</a></li>
                <li onclick="showVariableGroups()"><a href="#">Variables</a></li>
                <li><a href="#">Resolve</a></li>
                <li><a href="#">Installs</a></li>
                <li><a href="#">Log</a></li>
                <li><a href="#">Ping</a></li>
                <li><a href="#">Global</a></li>
                <li><a href="#">Security</a></li>
            </ul>
        </div><!-- /navbar -->

        <!-- These are the placeholder divs. Only one is shown at a time. -->
        <div data-role="header" data-theme="b">
            <h1 id="selectedTab"><span>Apps</span></h1>
        </div>

        <div id="appList">
            @Html.Partial("~/Views/PartialViews/AppList.cshtml", Model.Applications)
        </div>

        <div id="serverList">
            @Html.Partial("~/Views/PartialViews/ServerList.cshtml", Model.Servers)
        </div>

        <div id="variableGroupList">
            @Html.Partial("~/Views/PartialViews/VariableGroupList.cshtml", Model.VariableGroups)
        </div>

        <div id="app">
            @Html.Partial("~/Views/PartialViews/App.cshtml")
        </div>
    </body>    

    <script>
        $(function () {
            showApps();
        });

        function showApps() {
            hideAll();
            $('#appList').show();
            $('#selectedTab').text('Apps');
        }

        function showServers() {
            hideAll();
            $('#serverList').show();
            $('#selectedTab').text('Servers');
        }

        function showVariableGroups() {
            hideAll();
            $('#variableGroupList').show();
            $('#selectedTab').text('Variable Groups');
        }

        function hideAll() {
            $('#appList').hide();
            $('#serverList').hide();
            $('#variableGroupList').hide();
            $('#app').hide();
        }

        function showApp(id) {
            hideAll();
            $('#app').show();            
            window.appInitialize(id);
        }
    </script>    
</html>

The user can select Apps, and this partial view will be displayed:

@model IEnumerable<PrestoCommon.Entities.Application>

<ul data-role="listview" data-autodividers="true" @*data-filter="true"*@ data-count-theme="c" data-inset="true" data-divider-theme="d">
    @foreach (var app in Model)
    { 
        <li onclick="showApp('@app.Id');"><a href="#">@app.Name</a></li>
    }
</ul>

And if the user clicks an app from above, showApp() gets called (see index.cshtml, above) with the app ID getting passed to it. showApp() will then hide all the other divs and show the only the partial view that displays the app:

<script>
    $(function() {
        // Note: This will execute as soon as the main page is loaded.
    });

    function appInitialize(id) {
        $('#selectedTab').text(id);  // Show the name of the app in the header
        $('#text-14').val(id);  // Just show the ID for testing.
    }
</script>

<form>
    <div data-role="fieldcontain">
         <label for="text-14">Text input:</label>
         <input type="text" data-mini="true" name="text-14" id="text-14" value="">
    </div>
</form>

This is me totally guessing at an approach to make the site look like the user is staying on a single page. I'm hoping for a sanity check to let me know that this is right or it's way off. And if there are any issues with the code itself, I'd love to know what can be improved.

\$\endgroup\$
2
\$\begingroup\$

It's more of a personal preference thing, but I would recommend removing the onclicks in the following:

<li onclick="showApps()"><a href="#" class="ui-btn-active">Apps</a></li>
<li onclick="showServers()"><a href="#">Servers</a></li>
<li onclick="showVariableGroups()"><a href="#">Variables</a></li>

Instead, my recommendation would be to put a class on the links, say something like this:

<li><a href="#" class="navLink">Apps</a></li>
<li><a href="#" class="navLink">Servers</a></li>

Then in jquery, add something like the following:

$(".navLink").click(function (e) {
  var link = $(this);
  switch (link.text()) {
     case "Apps":
       $("#appList").fadeIn(500);
       break;
     case "Servers":
       $("#serverList").fadeIn(500);
       break;
  }
});

Also, for the partialviews, you cannot render javascript in those (that I've found), so the easiest way to ensure that you can jQuery those would be to add a

$(document).delegate(".appListItem", "click", function (e) {
   // Stuff to do when clicking an item in the appList.
});

Also, if you would prefer to not have to load all the partialviews on page load (something I've found can slow down a page's loadtime), you might try something along the lines of changing your navlinks to something like this:

<li><a href="@Url.Action("GetMyApps", "Apps")" class="topLevelNavLink">Apps</a></li>

And then in jQuery do this:

$(".topLevelNavLink").click(function (e) {
      var url = $(this).attr("href");
      $("#contentDiv").load(url);
   });

There are many different ways to do it, and it really is a matter of preference. Your way doesn't look bad, but it would drive my OCD through the roof with the onclicks in the html tags and the loading of the divs that are hidden when loading the page (I'm a firm believer in passing only as much data across the wire as is necessary to display what is expected - to improve performance (even if it's just a few milliseconds) and lower the bandwidth used). But again it's all a matter of preference.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Welcome to CodeReview, nick. Awesome first post. Hope you enjoy the site. \$\endgroup\$ – Legato Apr 6 '15 at 19:09
  • \$\begingroup\$ Thanks, Legato! I'm excited to be here. Good code reviews teach the reviewer as well as the submitter, so I'm hoping to leverage this to learn the trade a little better. \$\endgroup\$ – Bardicer Apr 6 '15 at 19:11

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.