2

I'm currently working on a ASP.NET MVC project. The sites of the web application are created with Bootstrap. Later I added some AngularJS script to be able to translate the page into different languages. This works fine for all the pages, but not so if a partial view is loaded from a page. So, for example I have a page to search for rollout objects by name or host name. On the page all the angular expressions in curly braces are evaluated properly and are replaced with strings in several languages by using a translate script. Now if I filter the objects by one of the three attributes the partial view for that page is loaded showing the results of the search, but here are the angular expressions not evaluated and it just shows the expressions themselves.

Here is the page where it works properly:

@{
    ViewBag.Title = "{{ 'ROLLOUT-OBJECT_MANAGEMENT.TITLE' | translate }}";
}

<!-- html -->
<div style="font-size: 20px; margin-top: 20px;  margin-bottom: 20px;">
    <div class="gray-background list-group-item" translate="{{'ROLLOUT-OBJECT_MANAGEMENT.TITLE'}}"></div>
</div>
<div class="list-group">

    <div class="gray-background list-group-item">
        <div class="row margin-bottom">
            <div class="col-md-3">
                <h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.FIRST_NAME'}}"></h6>
            </div>
            <div class="col-md-3">
                <h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.SURNAME'}}"></h6>
            </div>
            <div class="col-md-3">
                <h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.HOST_NAME'}}"></h6>
            </div>
        </div>
        <div class="row margin-bottom">
            <div class="col-md-3">
                <!-- referenced in getPartial() -->
                <input type="text" class="form-control" id="iFirstName" name="iFirstName" placeholder="">
            </div>
            <div class="col-md-3">
                <!-- referenced in getPartial() -->
                <input type="text" class="form-control" id="iSurName" name="iSurName" placeholder="">
            </div>
            <div class="col-md-3">
                <!-- referenced in getPartial() -->
                <input type="text" class="form-control" id="iHostName" name="iHostName" placeholder="">
            </div>
            <div class="col-md-3">
                <!-- getPartial() added to click through javascript-->
                <button type="submit" class="btn btn-primary btn-block" id="iButton"><span translate="{{'ROLLOUT-OBJECT_MANAGEMENT.BUTTON_SEARCH'}}"></span><span class="white-color glyphicon glyphicon-search"></span></button>
            </div>
        </div>
    </div>
</div>
<div class="list-group">
    <div class="gray-background list-group-item">
        <h5><span translate="{{'ROLLOUT-OBJECT_MANAGEMENT.RESULTS'}}"></span><span class="purple-color glyphicon glyphicon-globe"></span></h5>
    </div>
    <!-- referenced in getPartial() -->
    <div class="gray-background list-group-item">

        <div class="row">
            <div class="col-md-12" id="partialViewContainer">
                @{Html.RenderPartial("_RolloutObjectManagementResultsPartial");}
            </div>
        </div>
    </div>
</div>


<!-- layout -->
@Styles.Render(
  "~/content/chosen/chosen.css",
  "~/content/chosen/prism.css",
  "~/content/chosen/style.css",
  "~/content/bootstrap.css",
  "~/content/Site.css")

<!-- javascript -->
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/chosen/chosen.jquery.js"></script>
<script src="~/Scripts/chosen/prism.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
<script>
    var config = {
        '.chosen-select': {},
        '.chosen-select-deselect': { allow_single_deselect: true },
        '.chosen-select-no-single': { disable_search_threshold: 10 },
        '.chosen-select-no-results': { no_results_text: 'Oops, nothing found!' },
        '.chosen-select-width': { width: "95%" }
    }
    for (var selector in config) {
        $(selector).chosen(config[selector]);
    }
</script>
<script>
    //add functionality to button
    $('#iButton').click(function () {
        getPartial('0');
    });
</script>
<script>
    function previous() {
        var temp = document.getElementById("hPage").value;
        //alert(temp);//debug
        if (temp > 0) {
            temp = --temp;
        }
        getPartial(temp);
    }
    function next() {
        var temp = document.getElementById("hPage").value;
        //alert(temp);//debug
        temp = ++temp;
        getPartial(temp);
    }
</script>
<script>
    function getPartial(newPage) {
        //get search values
        var tempFirst = document.getElementById("iFirstName");
        var tempSur = document.getElementById("iSurName");
        var tempHost = document.getElementById("iHostName");
        var firstResult = tempFirst.value;
        var surResult = tempSur.value;
        var hostResult = tempHost.value;
        //ajax call
        $.ajax({
            url: "_RolloutObjectManagementResultsPartial",
            type: "POST",
            data: { firstName: firstResult, surName: surResult, hostName: hostResult, page: newPage, count: 10 },
            dataType: "html",
            error: function (xhr) {
                //alert(xhr.responseText);//debug
            },
            success: function (result) {
                $("#partialViewContainer").html(result).find("select").each(function () {
                    $(this).chosen({});
                })
            },
            complete: function () {
                //alert("everything worked");//debug
            }
        });
    }
</script>

And here is the partial view where it doesn't work (important are the expressions in {{...}}:

<!-- Import needed namespaces -->
@using RolloutTool.BusinessLayer.Foundation
@using RolloutTool.Utility

<!-- Initializing needed variables -->
@{
    List<RolloutObject> RolloutObjects = ViewContext.Controller.ViewBag.RolloutObjects;
    List<Cluster> Clusters = ViewContext.Controller.ViewBag.Clusters;
    string name = "";
    int count = 0;
    string rowID = "";
    int page = 0;
    if (ViewContext.Controller.ViewBag.Page != null)
    {
        page = ViewContext.Controller.ViewBag.Page;
    } 
}

<!-- html elements -->
<div class="row">
    <div class="col-md-12">
        <table class="table">
            <thead>
                <tr>
                    <th style="width:25%"><h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.EMPLOYEE'}}"></h6></th>
                    <th style="width:20%"><h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.WORK_STATION'}}"></h6></th>
                    <th class="text-center" style="width:15%"><h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.EDIT'}}"></h6></th>
                    <th class="text-center" style="width:25%"><h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.CLUSTER'}}"></h6></th>
                    <th class="text-center" style="width:15%"><h6 translate="{{'ROLLOUT-OBJECT_MANAGEMENT.ASSIGN'}}"></h6></th>
                </tr>
            </thead>
            <tbody>
                <!-- creating all RolloutObject Table rows -->
                @foreach (RolloutObject ro in RolloutObjects)
                {
                        <!-- generating rowID -->
                    rowID = "row" + Convert.ToString(count);
                    count++;
                        <!-- generating the full employee name -->
                    name = Functions.TryGetValue(ro.Employee.FirstName) + " " + Functions.TryGetValue(ro.Employee.SecondName) + " " + Functions.TryGetValue(ro.Employee.Name);
                    <tr id="@rowID">
                        <td>@name</td>
                        <td id="@Convert.ToString(rowID + "_hn")">@Convert.ToString(Functions.TryGetValue(ro.Hostname))</td>
                        <!-- generate link to right rolloutobjectedit -->
                        <td class="text-center"><a href="#"><span class="btn-pencil glyphicon glyphicon-pencil blue-color glyph-hov" onclick="location.href='@Url.Action("RolloutObjectEdit", "RolloutObject", new {hostName = ro.Hostname })'"></span></a></td>
                        <!-- generating the link for cluster addition and populating cluster dropdown -->
                        <td class="text-center">
                            <div class="row">
                                <div class="col-sm-12">
                                    <select class="chosen-select no-margin" style="width:100%" id="@Convert.ToString(rowID + "_cl")" name="iCluster" data-placeholder="Cluster">
                                        @if (ro.Cluster != null)
                                        {
                                            <option selected>@Convert.ToString(Functions.TryGetValue(ro.Cluster.Name))</option>
                                        }
                                        else
                                        {
                                            <option></option>
                                        }
                                        @foreach (Cluster cluster in Clusters)
                                        {
                                            <option>@Convert.ToString(Functions.TryGetValue(cluster.Name))</option>
                                        }
                                    </select>
                                </div>
                            </div>
                        </td>
                        <td class="text-center"><span class="btn-ok glyphicon glyphicon-ok green-color glyph-hov" onclick="callAjax('@rowID')" /></td>
                    </tr>
                }
            </tbody>
        </table>
    </div>
</div>

<div class="row">
    <div class="col-md-12">
        <input class="hidden" id="hPage" value="@Convert.ToString(page)" />
        <nav>
            <ul class="pager">
                <li class="pull-left"><a class="btn-paging glyphicon glyphicon-arrow-left" onclick="previous()"></a></li>
                <li class="pull-right"><a class="btn-paging glyphicon glyphicon-arrow-right" onclick="next()"></a></li>
            </ul>
        </nav>
    </div>
</div>

<!-- javascript -->
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/chosen/chosen.jquery.js"></script>
<script src="~/Scripts/chosen/prism.js"></script>
<script>
    function callAjax(idRow) {
        //get row values
        var tempTD = document.getElementById(idRow + "_hn");
        var tempSelect = document.getElementById(idRow + "_cl");

        var tempHostName = tempTD.textContent;
        var tempCluster = tempSelect.options[tempSelect.selectedIndex].text;

        //ajax call
        $.ajax({
            url: "AddToCluster",
            type: "POST",
            data: { clusterName: tempCluster, hostName: tempHostName },
            dataType: "html",
            error: function (xhr) {
                alert(xhr.responseText);
            },
            success: function (result) {
               
            },
            complete: function () {
                //alert("everything worked");//debug
            }
        });
    }
</script>
<script>
    function previous() {
        var temp = document.getElementById("hPage").value;
        //alert(temp);//debug
        if (temp > 0) {
            temp = --temp;
        }
        getPartial(temp);
    }
    function next() {
        var temp = document.getElementById("hPage").value;
        //alert(temp);//debug
        temp = ++temp;
        getPartial(temp);
    }
</script>
<script>
    function getPartial(newPage) {
        //get search values
        var tempFirst = document.getElementById("iFirstName");
        var tempSur = document.getElementById("iSurName");
        var tempHost = document.getElementById("iHostName");
        var firstResult = tempFirst.value;
        var surResult = tempSur.value;
        var hostResult = tempHost.value;
        //ajax call
        $.ajax({
            url: "_RolloutObjectManagementResultsPartial",
            type: "POST",
            data: { firstName: firstResult, surName: surResult, hostName: hostResult, page: newPage, count: 10 },
            dataType: "html",
            error: function (xhr) {
                alert(xhr.responseText);
            },
            success: function (result) {
                $("#partialViewContainer").html(result).find("select").each(function () {
                    $(this).chosen({});
                })
            },
            complete: function () {
                //alert("everything worked");//debug
            }
        });
    }
</script>

This is the _Layout.cshtml where the scripts are contained and loaded:

<!DOCTYPE html>
<html ng-app="myApp">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - {{ 'TITLE.PROGRAM' | translate }}</title>
    @Styles.Render(
    "~/Content/css",
    "~/Content/flag-icon-css-master/assets/docs.css",
    "~/Content/flag-icon-css-master/css/flag-icon.min.css",
    "~/Content/Site.css")
    <script src="~/Scripts/angular/angular.js"></script>
    <script src="~/Scripts/angular/angular-translate.js"></script>
    <script src="~/Scripts/angular/angular-cookies.min.js"></script>
    <script src="~/Scripts/angular/translate.js"></script>
    <script src="~/Scripts/angular/angular-route.min.js"></script>
    <script src="~/Scripts/angular/angular-translate-storage-cookie.min.js"></script>
    <script src="~/Scripts/angular/angular-translate-storage-local.min.js"></script>    
</head>

<body ng-controller="Ctrl">
  
  <!-- Here is the html for the navigation bar etc. -->
  
    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
</body>
</html>

I am really not an expert on AngularJS as I only wanted to provide some cool translation feature, but I hope you guys have an idea why it doesn't work in the partial views.

4
  • You need to add script code on top of the view where you register to RenderPartial view and ng-controller as well Commented Jan 21, 2015 at 4:35
  • So from what it looks like, you are using a JavaScript AJAX call to replace a DOM element with an HTML partial, which happens to include Angular expressions. Angular won't render the expressions properly, as expressions are evaluated during the $compile() phase, which creates a template to link to a scope. This normally occurs during the bootstrap phase, or a special function inside a directive. Commented Jan 21, 2015 at 4:50
  • Angular.js discourages direct DOM manipulation whenever possible, and it honestly looks like the logic you are trying to achieve would be easier and cleaner to code if you performed the entire process in Angular. That being said, I'm researching a bit more and will post a workable solution soon. Commented Jan 21, 2015 at 4:59
  • 1
    After doing a bit of research on the subject and looking for a solution, I can only say it appears that you need to refactor your application. consider using angular's $http service to populate variables you can evaluate rather than $.ajax to replace chunks of the DOM. The way you are building the DOM now will just not work with Angular. Commented Jan 21, 2015 at 5:28

1 Answer 1

1

Its just that you need to call the partial view using ng-include("'controller/action'"). Apostrophe(') is important while writing url.

Example

 <div id="TestDiv" ng-include="templateUrl"></div>

and inside the angular controller

 var app = angular.module("Layout", []);
    app.controller("LoadPage", function ($scope, $http, $sce) {

   //Initially
    $scope.templateUrl = '/Home/DefaultPage';

    // To dynamically change the URL.
    $scope.NewProjFn = function () {
        $scope.templateUrl = '/Home/ProjectPage';
    };
});

It might well not at all be difficult for you to re-implement it but by using ng-include you also need not to make an ajax call. It do it all by itself which includes ajax call, compilation and display. But the functions like ng-click and other events will not work as its a one time compilation process.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.