2

The solution to my problem can be found below.

I can not get my code to work. I need to send an AJAX call to an action method in my controller that has to return a string (for now). But when I activate the AJAX call, it returns the HTML source code of the page I'm currently on And it does not even hit the desired controller action.
This is my code:

Ajax call

<script>

    function addtoCart()
    {
        amount = prompt("Hoeveel producten wilt u toevoegen aan uw winkelwagen?", 1);
        //find product
        var product = {
            "id": '@Model.ID',
            "naam": "@Model.Naam",
            "afbeelding": "@Model.Afbeelding",
            "beschrijving": "@Model.Beschrijving",
            "prijs": "@Model.Prijs",
            "aantal": amount
        };
        $.ajax({
            url: '@Url.Action("storeProductInSession", "Product")',
            type: 'POST',
            data: JSON.stringify(product),
            dataType: 'json', //Right now, this gives an "Unexpected Token < error". This is probably because when the method returns the entire HTML document, it won't be able to render <!doctype html> as JSON.
            contentType: 'application/json; charset=utf-8',
            success: function (result)
            {
                console.log(result);
            },
            error: function (jqXHR, textStatus, errorThrown)
            {
                console.log(product);
                console.log(jqXHR);
                console.log(textStatus);
                console.log(errorThrown);
            },
            async: true
        });

        //sessionStorage.setItem('@Model.ID', JSON.stringify(product)); This is for later
    }

StoreProductInSession(The method that has to be called)

 [HttpPost]
        public string storeProductInSession(object product)/*, string naam, string afbeelding, string beschrijving, decimal prijs, int aantal)*/
        {
            return "This method is going to do session stuff, but for now it just has to return this string";

            //Get the POST input from the AJAX call

            //Add the input to a JSON array

            //add the array to the session

            //Return the array

            //let javascript convert that array to the cart <li>
        }

It still returns the entire HTML page, and even if the object product parameter is incorrect, I would be happy to see that the ajax call actually hits that method. I am thinking that there could be a problem between the call and my routing, but I am not sure. Here's that code:

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.MapRoute(
name: "Product",
url: "Product/{id}",
defaults: new { controller = "Product", action = "Index" }
);
        routes.MapRoute(
            name: "Categorie",
            url: "Categorie/{id}",
            defaults: new { controller = "Categorie", action = "Index" }
            );
        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Welkom", action = "Index", id = UrlParameter.Optional }
        );


    }

If I would even be able to simply give the ID to the StoreProductInSession action, I could work from there. I'm going to work with the user's session, so I think a GET would not be safe enough.

Solution

A big thanks to @Dolan for helping out! The problem was my routing!

Ajax Call

<script>

    function addtoCart()
    {
        amount = prompt("Hoeveel producten wilt u toevoegen aan uw winkelwagen?", 1);
        //find product
        var product = {
            "id": '@Model.ID',
            "naam": "@Model.Naam",
            "afbeelding": "@Model.Afbeelding",
            "beschrijving": "@Model.Beschrijving",
            "prijs": "@Model.Prijs",
            "aantal": amount
        };
        $.ajax({
            url: '@Url.Action("storeProductInSession", "Product")',
            type: 'POST',
            data: JSON.stringify(product),
            dataType: 'html', //I tried entering 'json' but that gave me a 'unexpected < token' error.
            contentType: 'application/json; charset=utf-8',
            success: function (result)
            {
                console.log(result);
            },
            error: function (jqXHR, textStatus, errorThrown)
            {
                console.log(product);
                console.log(jqXHR);
                console.log(textStatus);
                console.log(errorThrown);
            },
            async: true
        });
</script>

storeProductInSession

 [HttpPost]
        public string storeProductInSession(int id, string naam, string afbeelding, string beschrijving, decimal prijs, int aantal)
        {
            return String.Format("Product given to the ajax call: {0}, {1}, {2}, {3}, {4}, {5}", id, naam, afbeelding, beschrijving, prijs, aantal);
}

Routing

public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapRoute(
    name: "Product",
    url: "Product/{id}",
    defaults: new { controller = "Product", action = "Index" },
    constraints: new { id = "\\d+" }
);

            routes.MapRoute(
                name: "ProductAction",
                url: "Product/storeProductInSession",
                defaults: new { controller = "Product", action = "storeProductInSession" }
            );

            routes.MapRoute(
                name: "Categorie",
                url: "Categorie/{id}",
                defaults: new { controller = "Categorie", action = "Index" }
            );

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Welkom", action = "Index", id = UrlParameter.Optional }
                );


        }
2
  • 1
    Does this exist anywhere for testing? Are you able to access /Product/storeProductInSession/ directly in a browser and get a result? Commented Mar 3, 2015 at 15:37
  • @DonBoots It's a post, so I'll have to do some fiddling to test it. Just a heads up, though: I tried using my "test" action which also just returns a "it works" string (I used this earlier in development) and the ajax call does not reach that action either and it still prints the entire HTML page Commented Mar 3, 2015 at 16:17

2 Answers 2

2

You should use the URL helper:

url: '@Url.Action("storeProductInSession", "Product")',

For more information, see here.

OK, I think the issue with your product object. It is not an object, rather a string. The ' characters around your product object are the issue - JavaScript thinks it is a string - not an object. It should be something like this:

var product = {
            "id": "@Model.ID",
            "naam": "@Model.Naam",
            "afbeelding": "@Model.Afbeelding",
            "beschrijving": "@Model.Beschrijving",
            "prijs": "@Model.Prijs",
            "aantal": " + amount + "
        };

See here: http://jsfiddle.net/donal/mo776xe0/1/

Also, if you know id will be an integer, you can do this:

var product = {
            "id": @Model.ID,
            "naam": "@Model.Naam",
            "afbeelding": "@Model.Afbeelding",
            "beschrijving": "@Model.Beschrijving",
            "prijs": "@Model.Prijs",
            "aantal": " + amount + "
        };

Can you try this:

[HttpPost]
public string storeProductInSession(object product)
{
    return "This method is going to do session stuff, but for now it just has to return this string";

}

Looking at your routes, I can see the problem.

It is assuming storeProductInSession is the id of the Product you are looking for and therefore going to the Index action of the Product controller.

What we need is a constraint. A constraint will tell the route to only use it if the id is a number (digit). For example: constraints: new { id = @"\d+" }

Therefore, you need to change the routes to this (You also need a route for the Product/storeProductInSession action):

routes.MapRoute(
    name: "Product",
    url: "Product/{id}",
    defaults: new { controller = "Product", action = "Index" },
    constraints: new { id = "\\d+" }
);

routes.MapRoute(
    name: "ProductAction", 
    url: "Product/storeProductInSession", 
    defaults: new {controller = "Product", action = "storeProductInSession"}
);

routes.MapRoute(
    name: "Categorie",
    url: "Categorie/{id}",
    defaults: new { controller = "Categorie", action = "Index" }
);

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Welkom", action = "Index", id = UrlParameter.Optional }
    );

Therefore, when you are asking for Product/storeProductInSession. It will see that storeProductInSession is not a digit and then move on to the next route.

The next route will point it at the Product controller and the storeProductInSession action.

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

12 Comments

+1 for this! This would play better with your routing setup. The less places you need to change routes, the better!
@Donal, it still returns the HTML page, got any other nice tricks up your sleeve :)?
@S.tenBrinke ok, I think the issue is with your product object definition. JavaScript is treating it as a string - not an object. I have updated the answer with more info.
@Donal Nope! Still the entire page. I tried changing the datatype to json but it still returned the 'unexpected < token' error. The action does not even get hit, so maybe that's the problem?
@S.tenBrinke lol, just seeing that now. You are posting an object not a series of parameters - so you should expect an object. Can you try modifying the storeProductInSession method to just accept an object?
|
0

Try this, remove "dataType: html" and change this: (echo instead return):

[HttpPost]
        public string storeProductInSession(int id, string naam, string afbeelding, string beschrijving, decimal prijs, int aantal)
        {
            echo "This method is going to do session stuff, but for now it just has to return this string";

        }

2 Comments

Echo doesn't exist, right? Visual Studio says so, at least. Are you confused with PHP? Removing Datatype HTML also still returns the HTML page.
Yes, I was thinking in PHP! Sorry!

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.