Search code examples
angularjsasp.net-mvcurl-routing

@Url.Action returns HTTP Error 404.0 - Not Found


Why do my url action returns a not found error? I have a Recipes table which I generate using angular-datatables with each having a View button with the href link and id value to the Details view. Once in the details view I will need to get the id value in my angular controller.

Index.cshtml

@{
    ViewBag.Title = "Recipes";
}

<br />
<div class="col-md-12 center">
    <a href="/Recipes/Create"><input type="button" value="Create" class="btn btn-default" /></a>
</div>
<br/>
<br/>
    <div>
        <table datatable="tblRecipe" dt-options="showCase.dtOptions" dt-columns="showCase.dtColumns" dt-instance="showCase.dtInstance" class="table table-bordered"></table>
    </div>
    @*edit modal...*@

@section Scripts {
    @Scripts.Render("~/bundles/indexRecipe")
    }

indexRecipe.js Controller

var app = angular.module('app', ['datatables'])
app.controller('MainController', function ($scope, $window, $http, $filter, $timeout, $compile, DTOptionsBuilder, DTColumnDefBuilder, DTColumnBuilder, EditRecipe, $rootScope) {

    var vm = this;
    vm.message = '';
    vm.dtInstance = {};
    vm.Recipes = {};
    vm.delete = deleteRow;
    vm.edit = editRow;
    vm.Update = updateRow;
    vm.dtOptions = DTOptionsBuilder.newOptions()
    .withOption('ajax', {
        url: "/Recipes/GetAllRecipes",
        type: "POST"
    })
    .withOption('createdRow', createdRow)
    .withOption('select', true);
    vm.dtColumns = [
                    //....
                    DTColumnBuilder.newColumn(null).withTitle('Actions').notSortable().renderWith(actionsHtml)
    ];

    function createdRow(row, data, dataIndex) {
        // Recompiling so we can bind Angular directive to the DT
        $compile(angular.element(row).contents())($scope);
    }
    //function deleteRow(recipe)
    //function editRow(recipe
    function actionsHtml(data, type, full, meta) {
        vm.Recipes[data.Id] = data;
        return '<a title="View"  href="@Url.Action("Details", "Recipes", new { id = '+data.Id+' })">' +
            ' <i class="fa fa-eye" aria-hidden="true"></i>' + '</a>' + '<a title="Edit"  href="javascript:void(0)" ng-click="showCase.edit(showCase.Recipes[' + data.Id + '])">' +
            ' <i class="fa fa-pencil"></i>' + '</a>' + '<a title="Delete" href="javascript:void(0)" ng-click="showCase.delete(showCase.Recipes[' + data.Id + '])" )"="">' + ' <i class="fa fa-trash-o"></i>' + '</a>';
    };
    //function updateRow(recipe, ings, tags, files)

});
app.service("EditRecipe", function ($http) {
    this.EditById = function (recipe) {
        var response = $http({
            method: "post",
            url: '/Recipes/Edit',
            data: JSON.stringify(recipe)
        });
        return response;
    }
    this.Update = function (recipe, ings, tags, files) {
        var response = $http({
            method: "post",
            url: '/Recipes/Update',
            data: JSON.stringify(recipe)
        });
        return response;
    }
});

RecipesController

public ActionResult Details(int? id)
{
    if (id == null)
    {
        return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    Recipe recipe = db.Recipes.Find(id);
    if (recipe == null)
    {
        return HttpNotFound();
    }
    return View(recipe);
}

href="@Url.Action("Details", "Recipes", new { id = "+data.Id+" })" or href="@Url.Action("Details", "Details", new { id = "+data.Id+" })" or href="@Url.Action("Details", "Recipes")" returns the url below.

http://localhost:57104/Recipes/@Url.Action(

Error Code:    0x80070002

Solution

  • You cannot access Razor helper methods in a JS file. Razor syntax only work with .cshtml or .vbhtml files. So you can do something like below. Define a javascript variable in your .cshtml file and access it in your external JS file.

    Index.cshtml

    <script>
    var URL={
      Details:'@Url.Action("Details", "Recipes")',
    }
    </script>
    

    indexRecipe.js Controller

    return '<a title="View"  href='+URL.Details+'?id='+data.Id >' +
                ' <i class="fa fa-eye" aria-hidden="true"></i>' + '</a>' + '<a title="Edit"  href="javascript:void(0)" ng-click="showCase.edit(showCase.Recipes[' + data.Id + '])">' +
                ' <i class="fa fa-pencil"></i>' + '</a>' + '<a title="Delete" href="javascript:void(0)" ng-click="showCase.delete(showCase.Recipes[' + data.Id + '])" )"="">' + ' <i class="fa fa-trash-o"></i>' + '</a>';