0

I am making a web app using Laravel 8.

All of my controller functions are working, apart from the following:

  public function show(Request $id)
    {
        return response()->view('locations.show', compact('id'));
    }

I have made sure that this controller is being reached, but nothing happens and the page does not redirect to the view I specified.

web.php:

Route::get('/getlocation', [App\Http\Controllers\LocationController::class, 'show']);

When I try to access the route manually, the page displays the view.

Please let me know if you need additional information. Thanks.

EDIT: As requested some additional code.

javascript

$("#getLocation" + spot.ID).click(function () {
    $.get(getLocation, spot.ID);
});
  • getLocation is a variable declared in a script tag in app.blade.php:
var getLocation = '{{action('App\Http\Controllers\LocationController@show')}}';

Things I've Tried

  • Different ways of returning the view such as return view('locations.show', compact('id)); and return response()->view('locations.show', compact('id));.

  • Different ways of sending the variable to the view such as instead of compact() I tried ['id'=>$id].

  • Adding a variable to the route ('/getlocation/{id}) which required me changing the way the get request occurs to $.get('/getlocation/' + spot.ID, spot.ID);

EDIT2:

I have made a few changes, but the page is still not redirecting.

javascript:

$("#getLocation" + spot.ID).click(function () {
    $.post("/getlocation", JSON.stringify(spot));
});

web.php:

Route::post('/getlocation', [App\Http\Controllers\LocationController::class, 'show']);

Route::get("/showspot", function (Request $location) {
    return view('locations.show', compact('location'));
})->name("showLocation");

LocationController:

public function show(Request $location)
{
    return redirect()->route('showLocation', json_decode($location));
}

I was getting errors regarding parameters being missing after clicking the button, so I had to use JSON.stringify() and json_decode() in my javascript file and controller respectively. Now I am getting no errors when clicking the button, but the page is still not redirecting to the view requested.

I did notice in my cmd window running php artisan serve that when I click the button, requests are occurring: [Sun Dec 5 16:32:09 2021] 127.0.0.1:64795 Accepted [Sun Dec 5 16:32:10 2021] 127.0.0.1:64795 Closing

But again, not redirecting.

EDIT 3

More Details: What I'm trying to accomplish here is send the object from my javascript code to the locations.show view and redirect to that view. The javascript code shown is within a get request that fetches a JSON object and loops through it, displaying each object within the object.

$.each(jsonSpots, function (key, spot) {
    if (spot.NAME.search(inputExpression) != -1 || spot.TYPE.search(inputExpression) != -1) {
        results.push(spot);
        $('h3').html("Total: " + resultsCount);

        $('#result').append(
            '<li id="spot' + spot.ID + '" class="spot list-group-item">' +
            '<strong>Name: </strong>' + spot.NAME + '<br/>' +
            '<strong>Address: </strong>' + spot.ADDRESS + '<br/>' +
            '<button class="btn btn-info" id="getLocation' + spot.ID + '" >More Details</button>' +
            '<br>'
        );

        $("#getLocation" + spot.ID).click(function () {
            $.post(getLocation, spot, function (data) {
                if (data.success) { // data.success is a boolean
                    window.location.href = data.url;
                }
            });
        });

        if (authenticated) {
            $("#spot" + spot.ID).append(
                '<button type="button" class="btn btn-dark" id="addSpot' + spot.ID + '" >Add To Map</button>'
            );
            $("#addSpot" + spot.ID).click(function () {
                $.post(addSpot, spot);
                drawPins("all");
            });
        }

        $('#result').append('</li>');
    }
});

Thanks to @Daedalus response, I have more of an understanding of why what I was originally attempting to accomplish was not working, and since been able to accomplish my goal, with a few alterations to his suggestion:

javascript:

NOTES:

  • getLocation is a hardcoded action link within app.blade.php that points to my desired controller.
  • Sending the entire object instead of just ID, because one of the issues I was having was that I am only adding a Location object to the database if the user decides they want to save it to their map. Therefore, when Laravel would look for the Location associated with that ID, it wouldn't find anything and the request would fail.
$("#getLocation" + spot.ID).click(function () {
    $.post(getLocation, spot, function (data) { 
)
        if (data.success) {
            window.location.href = data.url;
        }
    });
});

web.php:

NOTES:

  • Sent a compacted Request to the controller instead of a Location object, for the reason stated above
Route::post('/getlocation', [App\Http\Controllers\LocationController::class, 'show']);

Route::get("/showspot", function (Request $location) {
    return view('locations.show', compact('location'));
})->name("showLocation");

Controller:

NOTES:

  • At first I tried to just send the $location, but I able to access all of the properties I needed except for the first one for some reason, which was NAME. So instead, I sent in an object with all the properties.
public function show(Request $location)
{
    return [
        'success' => true,
        'url' => route('showLocation',
            [
                'NAME' => $location->NAME,
                'LONGITUDE'=> $location->LONGITUDE,
                'LATITUDE' => $location->LATITUDE,
                'ADDRESS' => $location->ADDRESS,
                'TYPE' => $location->TYPE,
                'ID' => $location->ID
            ])
        ];
}

Now, all of the parameters are showing in the URL, which I would like to get around.

I realize that this is not a great way of accomplishing what I need, so any additional suggestions would be much obliged.

Emank
  • 23
  • 5
  • should not be: /getlocation /{id} ? do you have a model called Reqeust, or it is just normal request? – OMR Dec 04 '21 at 05:12
  • 2
    Typically, you just do `return view()` instead of `return response()->view()`, but I just tried locally, and that's not a problem per-se. Can you explain the issue in more detail? What button/link are you pressing to hit the `show()` method? What do you mean "redirect"; there's no redirect here (i.e. `return redirect() ...`)? How do you "manually" access this and why does that work? – Tim Lewis Dec 04 '21 at 05:27
  • @OMR I tried /getlocation/{id} as well. I should have mentioned. Same thing was happening. I do not have a model called Request. It is just a normal request. – Emank Dec 04 '21 at 05:56
  • @TimLewis I should have mentioned, I tried just `return view()`, as well as `redirect()`. I will edit the post and include the get request. By "manually" I meant by entering the url "/getlocation" with a hardcoded value instead of using the `$id` parameter. – Emank Dec 04 '21 at 06:00
  • It does not show the view specified. What does it actually do? – apokryfos Dec 04 '21 at 06:05
  • @apokryfos When I click the button that triggers the get request, the view does not appear. When I look at the console no errors appear and when I look at the networking tab I see that the request returned code 200. – Emank Dec 04 '21 at 06:08
  • 3
    `$.get(getLocation, spot.ID);` you aren't doing anything with the result here. You're just sending the request. You need to provide a 3rd parameter of a function that is called when the get request succeeds. Read https://api.jquery.com/jquery.get/ for more info – apokryfos Dec 04 '21 at 07:09
  • @apokryfos I was messing around with different ajax requests. I am using the ajax request to send the data to my controller, which then should allow me to use the data in my view. I have edited my post with updated code. – Emank Dec 05 '21 at 21:43
  • Can you show the request in your browser's developer tools, specifically the network tab? – Daedalus Dec 05 '21 at 21:48
  • @Daedalus There are two, one for getlocation and one for showspot. The status for both are 302, and 200 respectively. I'm not sure how to show you the request itself. I have the option to copy the request headers, is this what you would like to see? – Emank Dec 05 '21 at 21:59
  • @Daedalus my original reply had 202 for the second one -- that was a typo i have corrected it to 200. – Emank Dec 05 '21 at 22:02
  • @Emank A 302 means it is redirecting. You just don't do anything with the redirect; what do you expect to happen with the ajax request? – Daedalus Dec 05 '21 at 22:08
  • @Emank I realize you have yet to respond to my question, but it's too late to edit my other comment. An ajax request is incapable, by itself, of redirecting the page it is coded within. If you want js to redirect, you have to use `window.location.href = 'new url here';`, otherwise, while the ajax request will follow any redirects and return the response data(provided you do something with that data, as ajax requests return Promises), they won't actually change the page if the page they're requesting redirects. – Daedalus Dec 05 '21 at 22:23
  • @Daedalus What I'm trying to accomplish here is send the object from my javascript code to the locations.show view and redirect to that view. From what I understand from your reply, I am going about this the wrong way. How should I be doing this? – Emank Dec 05 '21 at 22:32
  • @Emank I posted an answer containing my thoughts on the matter. – Daedalus Dec 06 '21 at 00:19

1 Answers1

0

There are a few methods to go about achieving your goal here. However, it is important to understand why your original attempts did not work.

$("#getLocation" + spot.ID).click(function () {
    $.post("/getlocation", JSON.stringify(spot));
});

This snippet only sends a POST request to /getlocation. It doesn't do anything with the response data. Usually, if you wanted the currently-active page to react or respond to that request, you'd need to add an extra anonymous function as the last parameter to that method, like so:

$("#getLocation" + spot.ID).click(function () {
    $.post("/getlocation", JSON.stringify(spot), function (data) {
        // Do something with the data variable
    });
});

data, in this case, as defined by the documentation for $.post, is an intelligently-guessed data-type depending on what the server sends back. It could be JSON, xml, or something else, such as a plain string. In the case of your code, data would likely be a string of html(of the view) from the redirect the server side code sends in response.

Ajax follows redirects, but it doesn't change the currently active page unless you code it to.

Now, that said, the way I would do this is quite a bit simpler. Since you already want there to be a redirect, there's probably no real point to using ajax at all. You could just use a form and have the handler for that form's POST request return the redirect to the page you want to end up at.

However, on the assumption that your code is a bit more complex than that, and the simple method isn't possible, I'd do this:

Javascript:

$("#getLocation" + spot.ID).click(function () {
    $.post("/getlocation/" + spot.ID, function (data) {
        if (data.success) { // data.success is a boolean
            window.location.href = data.url;
        }
    });
});

Based on your code and writing, I'm going to assume that Location is a model. By casting $location to Request, you're not likely getting what you think you are; the Request class is defined here. Anyway, based on that assumption, you should use that model and type hint it instead:

Routes:

use App\Models\Location; // Assuming this is where your model is.

Route::post('/getlocation/{location}', [App\Http\Controllers\LocationController::class, 'show']);

Route::get("/showspot/{location}", function (Location $location) {
    return view('locations.show', compact('location'));
})->name("showLocation");

Controller:

public function show(Location $location)
{
    return [
        'success' => true,
        'url' => route('showLocation', ['id' => $location->id]);
    ];
}

success can of course change depending on what you're actually doing. Laravel has the ability to take a returned array from a route handler and transform it into JSON, so no need to redo that part. Route-model binding is explained more in-depth here.

In response to your third edit, that can be achieved by using Javascript to create a form element, add inputs to that element, and then submit that form with a POST request to the desired action url. Example below:

Controller:

public function show(Request $location)
{
    return [
        'success' => true,
        'url' => route('showLocation'),
        'location' => [
            'NAME' => $location->NAME,
            'LONGITUDE'=> $location->LONGITUDE,
            'LATITUDE' => $location->LATITUDE,
            'ADDRESS' => $location->ADDRESS,
            'TYPE' => $location->TYPE,
            'ID' => $location->ID
        ]
    ];
}

Javascript:

$("#getLocation" + spot.ID).click(function () {
    $.post("/getlocation/" + spot.ID, function (data) {
        if (data.success) { // data.success is a boolean
            let formEl = document.createElement('form');
            formEl.method = 'POST';
            formEl.action = data.url;
            
            Object.keys(data.location).forEach(function (key) {
                let inputEl = document.createElement('input');
                inputEl.type = 'hidden';
                inputEl.name = key;
                inputEl.value = data.location[key];
                formEl.appendChild(inputEl);
            });
            
            document.body.appendChild(formEl);
            formEl.submit();
        }
    });
});

Your other code on the page you're redirecting to can stay the same, assuming of course you access the Request class and assign NAME, LONGITUDE, etc. to the view.

This idea was gotten from here, so I'd recommend giving that answer an up vote when you can.

Daedalus
  • 7,586
  • 5
  • 36
  • 61
  • I have edited my question as it got closed due to lack of details, and have added my altered implementation of your suggestion. Thank you very much for your in depth explanation and resources on why my original attempt was not working. :D Would be great if you could point me in the right direction for getting rid of the parameters in the URL. – Emank Dec 06 '21 at 01:53
  • 1
    @Emank You'd have to dynamically create a form element and submit it, instead of doing `window.location.href = 'new url here'`; this form would create a POST request to the page in question, allowing the variables/data to be in the request instead of in the url. This is defined more in-depth [here](https://stackoverflow.com/questions/133925/javascript-post-request-like-a-form-submit). – Daedalus Dec 07 '21 at 23:25
  • I see, thank you very much! – Emank Dec 08 '21 at 03:36