根据id切换MVC表行的可见性

时间:2013-06-15 15:51:36

标签: javascript ajax toggle row visibility

在我的MVC Razor视图中,我有一个表,其中的行表示层次结构的两个级别。可以单击每一行以通过ajax调用加载partialview内容区域。这很好。

为了拥有一个更紧凑的列表,我现在想把桌子变成一个“轻型可折叠树视图”。仅当单击其标题行时,才应显示第二级中的行。单击另一个标题行时,应折叠/使所有当前子行不可见,并展开新的子集。

我主要是一个代码隐藏的人,并不习惯客户端脚本。我已经尝试了几种方法,但到目前为止还没有成功。我已经阅读了一些建议,但它们都略有不同,并且不能直接应用。这是我目前的尝试:

<table style="width: 100%;">
    <tr>
        <td style="width: 30%; vertical-align: top;">
            <table id="myTableTree" style="width: 100%;">
                @foreach (var testSuite in Model.TestSuites)
                {
                    <tr>
                        <th colspan="2" style="text-align: left;">
                            @Ajax.ActionLink(testSuite.Description, "GetContent", new { testSuiteId = testSuite.Id }, new AjaxOptions { UpdateTargetId = "subContent" }, new { onClick = "setShowState(" + testSuite.Id + ");" })
                        </th>
                    </tr>
                    foreach (var testCase in testSuite.TestCases)
                    {
                    <tr itemprop="@testSuite.Id" style="display: none;">
                        <td>&nbsp;</td>
                        <td>
                            @Ajax.ActionLink(testCase.Description, "GetContent", new { testCaseId = testCase.Id }, new AjaxOptions { UpdateTargetId = "subContent" })
                        </td>
                    </tr>
                    }
                }
            </table>
        </td>
        <td style="vertical-align: top;" id="subContent"></td>
    </tr>
</table>

<script type="text/javascript">
    function setShowState (testSuiteId)
    {
        var rows = document.getElementById('myTableTree').rows;
        for (var i = 0; i < rows.length; i++)
        {
            var row = rows.item(i);
            if (row.attributes['itemprop'] == testSuiteId)
                row.style.display = 'block';
            else
                row.style.display = 'none';
        }
    };
</script>

如您所见,所有子行最初都设置为display = none。我抓住了一个任意属性来保存每个第二级行的第一级ID。 itemprop似乎和任何一样好。在第一级行,我添加了一个引用javascript函数的onClick调用。 setShowState函数的目的是循环所有行并为行设置适当的可见性。当我检查生成的页面源它看起来像我期望的方式,但不起作用。从不扩展子行。

1)设置初始服务器返回行display = none然后在客户端切换是否可以?

2)是否可以让actionlink触发ajax服务器调用并触发客户端脚本来设置可见性?或者将ajax调用移动到java脚本只进行一次调用会更好吗?

3)使用display = block / none或visibility = visible / collapse进行切换是否更好?它真的会有什么不同吗?

4)使用itemprop存储父ID是否可以?我看到许多人使用类属性来处理类似情况。可以将class属性与纯整数值一起使用吗?

5)以我想要的方式切换行的最快方法是什么?循环所有行太慢了?我将有10-20个标题行,每行包含2-10个子行。

6)整个设计是不是很糟糕?我没有在MVC工具箱中找到树视图控件,因此我决定采用这种方式。我认为这看起来至少和树视图一样好,但也许另一种方法会更好?

7)jQuery会有什么帮助吗?我在布局页面中包含了jQuery库,但我不知道如何使用它。

1 个答案:

答案 0 :(得分:1)

在表达详细问题之前,很多次澄清。经过稍微检查后,我意识到我错过了解析属性的语法。这个例子现在完全正常工作:

<table style="width: 100%;">
    <tr>
        <td style="width: 30%; vertical-align: top;">
            <table id="myTableTree" style="width: 100%;">
                @foreach (var testSuite in Model.TestSuites)
                {
                    <tr>
                        <th colspan="2" style="text-align: left; border: 0;">
                            @Ajax.ActionLink(testSuite.Description, "GetContent", new { testSuiteId = testSuite.Id }, new AjaxOptions { UpdateTargetId = "subContent" }, new { onClick = "setShowState(" + testSuite.Id + ");" })
                        </th>
                    </tr>
                    foreach (var testCase in testSuite.TestCases)
                    {
                    <tr data-testSuiteId="@testSuite.Id" style="visibility: collapse;">
                        <td style="width: 10%; border: 0;">&nbsp;</td>
                        <td style="border: 0;">
                            @Ajax.ActionLink(testCase.Description, "GetContent", new { testCaseId = testCase.Id }, new AjaxOptions { UpdateTargetId = "subContent" })
                        </td>
                    </tr>
                    }
                }
            </table>
        </td>
        <td style="vertical-align: top;" id="subContent"></td>
    </tr>
</table>

<script type="text/javascript">

    // Toggle each section independantly
    function setShowState(testSuiteId) {
        var rows = document.querySelectorAll('[data-testSuiteId="' + testSuiteId + '"]');
        for (var i = 0; i < rows.length; i++) {
            var row = rows.item(i);
            row.style.visibility = (row.style.visibility == 'visible') ? 'collapse' : 'visible';
        }
    };

    // Alternative algorithm
    // Always collapse previous section when a new one is selected
    function setShowState2(testSuiteId) {
        var rows = document.getElementById('myTableTree').rows;
        for (var i = 0; i < rows.length; i++) {
            var row = rows.item(i);
            if (row.getAttribute('data-testSuiteId') == testSuiteId)
                row.style.visibility = 'visible';
            else if (row.getAttribute('data-testSuiteId') != null)
                row.style.visibility = 'collapse';
        }
    };
</script>

我建议对我自己的问题给出以下答案:

1)是的,设置属性然后在客户端切换是完全正常的。

2)是的,似乎可以触发一个服务器端操作并同时触发一个客户端。

3)我试过了。在我的情况下,它似乎同样适用于:显示和可见性。从进一步阅读中我了解到大多数情况下都会使用显示,但表中的可见性略好一些,因为不需要重新计算大小等表格属性。

4)itemprop属性有效。但在HTML5中,建议使用data属性。所以我用“data-testSuiteId”交换了“itemprop”。

5)可能有更快的方法,但这对我来说是可以接受的。

6)替代控制?

7)使用jQuery可以实现同样的目的。这将使代码更紧凑,实际上也更快。

// Toggle section
function setShowState(testSuiteId) {
    $("[data-testSuiteId='" + testSuiteId + "']").toggle();
};

// Display one section and collapse all others
function setShowState(testSuiteId) {
    $("[data-testSuiteId]").hide();
    $("[data-testSuiteId='" + testSuiteId + "']").show();
};