18

I am building in laravel 5.1 using angularJs.

When the user clicks a button, I want to send a destroy request to delete it from the database and then when thats completed send a get request to get the new data now that one has been deleted.

So I attached my method to an ng-click event on a button, this works, it hits the method.

I then run a .destroy request. Inside the .then() method of that .destroy I want to then call another method which has a .get request.

This works perfectly in Safari, but doesn't work in Chrome or Firefox.

Here is my code for the controller, the method that is called on button click to delete is deleteOpportunity():

$scope.getOpportunities = function()
    {
        UBOService.get()
            .then(function successCallback(responsed) {
                $scope.opportunities = responsed.data;
            }, function errorCallback(response) {
                $scope.error = response;
            });
    }
$scope.deleteOpportunity = function()
    {

                UBOService.destroy($scope.activeItem.id)
                    .then(function successCallback(response) {
                        $scope.getOpportunities();

                        return false;
                    }, function errorCallback(response) {
                        $scope.error = response;
                    });

    }

My service code:

app.service('UBOService', function($http) {

    return {
        get : function() {
            return $http.get('/api/user-booked-opportunities');
        },

        destroy : function(id) {

            return $http.delete('/api/user-booked-opportunities/' +  id);
        }
    }
})

Am I doing something wrong? Is there something I am missing? How does Safari interact differently with this code which makes it work?

RSM
  • 14,540
  • 34
  • 97
  • 144
  • 1
    Are any exceptions getting written to console? If not, is it even getting to the $http.get call? – cDecker32 Mar 04 '16 at 21:56
  • 1
    Hi! I just finished a project with L5.1 and AngularJS 1.47. Can i suggest you to use .finally() after your "then" block instead of ",function()". Additionally i would like to suggest you to not make any http calls after deleting something, but removing those objects from the variable you store your data in. If you want further clarification i can give you more info and code examples in separate comment. :) – Cowwando Mar 08 '16 at 08:15
  • 1
    What is not working in Safari? The delete request? or the get request? or the button click itself? Also what type of controller are you using in your laravel part? Any errors in console? – Keerthi Kumar P Mar 08 '16 at 12:00
  • You might have other issues, but to save yourself some calls, you could just return the new list of opportunities when you destroy one, so you don't have to make a seperate call. Orrrr I just read @Cowwando 's comment, do what he said, that is how I normally do it. – ribsies Mar 10 '16 at 07:37
  • Does it help to put the semi-colon in `} $scope.deleteOpportunity = function() {` as this: `}; $scope.deleteOpportunity = function() {` – Mark Schultheiss Mar 10 '16 at 20:22
  • What is the error thrown by Firefox and Chrome? – jonystorm Mar 11 '16 at 06:20
  • Could you post a screenshot of the console logs in Chrome and Firefox? – Cosmin Ababei Mar 11 '16 at 07:30

3 Answers3

3

It's tough to gauge from the parameters you posted, but just based on you saying that this works perfectly in Safari, but doesn't work in Chrome or Firefox, it sounds like this could be a CORS issue.

Firefox and Chrome have different requirements for cross-origin requests than Safari. Is your Laravel api endpoint for this destroy action located at the same location as your Angular app? What Access-Control-Allow-Origin header is the API returning?

Try adding something like the following to Laravel and see if it makes it this block consistent across those browsers:

App::before(function($request) {
  // Enable CORS 
  // In production, replace * with http://yourdomain.com 
  header("Access-Control-Allow-Origin: *");
  header('Access-Control-Allow-Credentials: true');

  if (Request::getMethod() == "OPTIONS") {
    // The client-side application can set only headers allowed in Access-Control-Allow-Headers
    $headers = [
      'Access-Control-Allow-Methods' => 'POST, GET, OPTIONS, PUT, DELETE',
      'Access-Control-Allow-Headers' => 'X-Requested-With, Content-Type, X-Auth-Token, Origin, Authorization'
    ];
    return Response::make('You are connected to the API', 200, $headers);
  }
});

(^ source)

wesww
  • 2,863
  • 18
  • 16
2

I guess its a CORS issue. And moreover this issue normally happens if you decouple your client side from your server side. You need to create a before middleware to handle such issues.

namespace App\Http\Middleware;

use Closure;

class BeforeMiddleware
{
  /**
  * Handle an incoming request.
  *
  * @param  \Illuminate\Http\Request  $request
  * @param  \Closure  $next
  * @return mixed
  */
 public function handle($request, Closure $next)
 {
    /** 
    * The access control allow origin and 
    * allow credential is set to * and true 
    * because i allow request from different domains
    * to hit the server
    */
    header('Access-Control-Allow-Origin: *');
    header('Access-Control-Allow-Credentials: false');
    header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS');
    header('Access-Control-Allow-Headers: Origin, Content-Type, Accept, Authorization');

    if ($request->getMethod() == "OPTIONS") {
        $headers = array(
            'Access-Control-Allow-Methods'=> 'POST, GET, OPTIONS, PUT, DELETE',
            'Access-Control-Allow-Headers'=> 'X-Requested-With, content-type',);
        return Response::make('', 200, $headers);
    }

    return $next($request);
 }
}

And at the angular side of things add this config block

app.config(['$httpProvider', function ($httpProvider) {

  $httpProvider.defaults.useXDomain = false;
  $httpProvider.defaults.withCredentials = false;
  delete $httpProvider.defaults.headers.common['X-Requested-With'];

}]);
oseintow
  • 7,221
  • 3
  • 26
  • 31
0

If you return a value in the successCallback or errorCallback, the returned value will be used to resolve the promise. Try to define a $q.deferred that will be resolved on get $http sucess with the data.

$scope.deleteOpportunity = function() {
            var deferred = $q.defer();

            UBOService.destroy($scope.activeItem.id)
                .then(function successCallback(response) {
                    UBOService.get().then(function(response){
                        $scope.opportunities = response.data;
                        deferred.resolve(response.data);
                    };
                }, function errorCallback(response) {
                    $scope.error = response;
                });
        return deferred.promise;
}
pdorgambide
  • 1,787
  • 19
  • 33