GitHub Tree Slider implementation on MVC3

I'm trying to implement the same tree slide in my MVC3 app and I'm not entirely sure I'm doing it right:

Index page:

<script type="text/javascript">
    $(document).ready(function () {
        $('#slider a').click(function () {
            history.pushState({ path: this.path }, '', this.href);
            $.get(this.href, function (data) {
                $('#slider').slideTo(data);
            });
            return false;
        });
    });
</script>

@{Html.RenderAction("MainTableTracker", "Release", new { releaseId = Model });}

MainTableTracker partial view:

<script type="text/javascript">
    $(document).ready(function () {
        $('#slider a').click(function () {
            history.pushState({ path: this.path }, '', this.href);
            $.get(this.href, function (data) {
                $('#slider').slideTo(data);
            });
            return false;
        });
    });
</script>

<div id="slider">
    @Html.RouteLink(Model.Brand.Name, "Brand", new { BrandId = Model.Brand.Id }) /
    <ul>
        <li><a href="#">Overview</a></li>
        @foreach(var model in Model.ModelExts)
        {
            <li>@Html.RouteLink(model.Model.Name, new { modelId = model.Model.Id })</li>
        }
    </ul>
</div>

VersionTable partial view:

<script type="text/javascript">
    $(document).ready(function () {
        $('#slider a').click(function () {
            history.pushState({ path: this.path }, '', this.href);
            $.get(this.href, function (data) {
                $('#slider').slideTo(data);
            });
            return false;
        });
    });
</script>


<div id="slider">
    @Html.RouteLink(Model.Brand.Name, "Brand", new { BrandId = Model.Brand.Id }) / @Html.RouteLink(Model.Name, "Model", new { modelId = Model.Id }) /
    <ul>
        <li><a href="#">Overview</a></li>
        @foreach(var model in Model.Brand.Model)
        {
            <li>@Html.RouteLink(model.Name, new { modelId = model.Id })</li>
        }
    </ul>

    <div class="versionWraper">
        @foreach(var version in Model.Version)
        {
            <div>
                @version.Name
            </div>
        }
    </div>
</div>

This works, however I'm pretty sure I'm doing it wrong, I'm guessing I shouldn't have 3 different views copying the code of the parent view everytime.

I'm wondering if I should just have one viewmodel and one action and let the view decide what to display everytime? But I'm not really happy about using just one action to display different types of data (Release, Brand and Feature).

Also, the layout has:

 $(window).bind('popstate', function (e) {
        $.get(e.originalEvent.state.path, function (data) {
            $('#slider').slideTo(data);
        });
    });

That works, but when I go back to the Brand level, it will reload all my scripts (being that it's a View not a Partial for the default one).

Is there any better way of implementing this?

Thanks

Answers


When designing something like this, I would encourage you not to target the objects by ID. It puts you in odd situations like the one you're facing, where you want to guarantee that the item is on the page before the script fires and that sort of thing - which can be inherently problematic when dealing with partial loading and such.

Consider, instead, this sort of approach:

<style>
    .slider { /* Styles here */ }
    .slider > ul { /* Styles here */ }
    .slider > ul > li { /* Styles here */ }
    .slider > .versionWrapper { /* Styles here */ }
    .slider > .versionWrapper > .versionName { /* Styles here */ }
</style>

<div class="slider">
    @Html.RouteLink(Model.Brand.Name, "Brand", new { BrandId = Model.Brand.Id })
    / @Html.RouteLink(Model.Name, "Model", new { modelId = Model.Id }) /
    <ul>
     <li><a href="#">Overview</a></li>

    @foreach(var model in Model.Brand.Model) {
     <li>@Html.RouteLink(model.Name, new { modelId = model.Id })</li>
    }

    </ul>
    <div class="versionWrapper">

    @foreach(var version in Model.Version) {
     <div class="versionName">@version.Name</div>
    }

    </div>
</div>

<script type="text/javascript" language="javascript">
$(document).ready(function () {
    $('.slider > ul > li > a').live('click', function (ev) {
        ev.preventDefault();
        ev.stopPropagation();

        var $a = $(ev.target);
        var $slider = $a.closest('.slider');

        history.pushState({ path: $a.path }, '', $a.href);
        $.get($a.href, function (data) {
            $slider.slideTo(data);
        });
    });
});
</script>

At this point, you are effectively targeting ANY slider you put on the page, regardless of what partial it is wrapped in - and the small amount of jQuery logic at the end can be easily put in a site-wide or page-wide JS file, decoupled from the specific implementation which outputs your HTML.

Next, simply create a toggle for which mode you're in. I like doing this with ViewData["SettingName"], but that's just me.

If you want your "MainTable" style view to display, set something like:

ViewData["Mode"] = "Default";

If you want your "Version" style view to display, set:

ViewData["Mode"] = "Version";

Then alter your partial to render as:

<div class="slider">
@{
    bool versionMode = (ViewData["Mode"] as String == "Version");

    string breadCrumb = Html.RouteLink(
        Model.Brand.Name, 
        "Brand", 
        new { BrandId = Model.Brand.Id }
    ).ToString();

    if (versionMode) {
        breadCrumb = String.Format("{0} / {1}", 
            breadCrumb, 
            Html.RouteLink(
                Model.Name, 
                "Model", 
                new { modelId = Model.Id }
            ).ToString()
        );
    }
}

    @breadCrumb /
    <ul>
        <li><a href="#">Overview</a></li>
@{
    if (versionMode)
        foreach(var model in Model.ModelExts) {

        <li>@Html.RouteLink(model.Model.Name, new { modelId = model.Model.Id })</li>

        }
    } else {

        @foreach(var model in Model.Brand.Model) {
            <li>@Html.RouteLink(model.Name, new { modelId = model.Id })</li>
        }

    }
}
    </ul>

@{
    if (versionMode) {

    <div class="versionWrapper">
        @foreach(var version in Model.Version) {
        <div>@version.Name</div>
        }
    </div>

    }
}

</div>

Need Your Help

IDLE for Python - tracing only my variables in Debug mode

python debugging python-idle

I'd like to use IDLE's Debug mode to watch my variables. Unfortunately the Local and Global lists in the Debug window are filled with hundreds of classes, types and functions, which must be from

Java Generics lowerbound

java generics

Could anyone please let me know why this doesn't work?