0

I'm currently learning angular, with spring boot as a server side also as a database, which mean I just had list of items in a class in spring boot to fetch the data from, just to learn how to use it.

anyway, I did display and update they work fine and well, but when I try to do the delete, it gets blocked by the has been blocked by CORS policy

although I put this annotation at the begging of the rest controller

@CrossOrigin(origins = "http://localhost:4200" ) 

yet everything works fine except the deleting function,

I'll attach everything, and I hope you guys can help me out.. I know it's a lot of file, but if you guys can give me any lead, because I'm watching tutorials and learning on my own

i keep getting method not allowed error 4o5 enter image description here

this is the HTML ...

<h1>To Do List :</h1>

<div class="aler alert-warning"    *ngIf='error'> {{successMessage}} </div> 


<br>
<div class="container">
<table class="table" style="width:100%" >
        <tr>
          <th  style='background-color: gray' >ID</th>
          <th  style='background-color: gray'>ToDO</th> 
          <th  style='background-color: gray'>Date</th> 
          <th  style='background-color: gray'>Delete</th> 
          <th  style='background-color: gray'>Update</th> 

        </tr>
        <!-- enhanced forloop  for( todo todo1 : todoList ) -->
        <tr *ngFor="let todo1 of todoList">
          <td>{{todo1.id}}</td>
          <td>{{todo1.description}}</td> 
          <td>{{todo1.targetDate}}</td> 

          <td><button (click)="deleteTodo(todo1.id)" class="btn btn-warning"> Delete </button></td> 
          <td><button (click)="updateTodo(todo1.id)" class="btn btn-success"> Update </button></td> 

        </tr>

      </table>
    </div>

this is the ts file

import { Component, OnInit } from '@angular/core';
import { HardCodedAuthenticationService } from '../service/hard-coded-authentication.service';
import { TodoDataService } from '../service/data/todo-data.service';
import { connectableObservableDescriptor } from 'rxjs/internal/observable/ConnectableObservable';
import { Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';


export class Todo {
  constructor(
    private id: number,
    private username: string,
    private description: string,
    private isDone: boolean,
    private targetDate: number,
  ) { }
}



@Component({
  selector: 'app-to-do-list',
  templateUrl: './to-do-list.component.html',
  styleUrls: ['./to-do-list.component.css']
})

export class ToDoListComponent implements OnInit {

  todoList: Todo[];
  successMessage: String;

  constructor(
    private todoService: TodoDataService,
    private router: Router,
    private http: HttpClient
  ) { }




  ngOnInit() {
    // on running 
    this.todoService.retrieveAllTodos('ayman').subscribe(
      response => {
        console.log(response)
        this.todoList = response
      }

    )
  }

  // handle delete todo button 
  deleteTodo(id) {
    console.log(`deleted ${id}`);
    this.todoService.deleteTodo1('ayman', id).subscribe(
      response => {
        console.log(response);
        this.successMessage = `deleted successfully ${id}`
      },
      error => {
        console.log(error.error);
      }
    )



  }



  // handle update todo button 
  updateTodo(id) {
    console.log(`update ${id}`);
    this.router.navigate(['todos', id]);
  }
}

AND THIS IS THE DAtTA SERVICE FILE

// import { Injectable } from '@angular/core';
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';


class HelloWorldBean2{
  constructor(public message : string){}
}



@Injectable({
  providedIn: 'root'
})
export class WelcomeDataService {


  // adding HTTP Client to connect with the server .. 
  constructor(
    private http : HttpClient

  ) { }



  // http://localhost:8080/hello-world-bean 
  excuteHelloWorldBeanSerivece(){
    // <hellWorlBean2> is what response Im expecting ..
    return(this.http.get('http://localhost:8080/hello-world-bean') ) ;

  }


// http://localhost:8080/hello-world/path/ayman 

  excuteHelloWorldBeanSeriveceWithPath(name:string){
    // <hellWorlBean2> is what response Im expecting ..
    return(this.http.get(`http://localhost:8080/hello-world/path/${name}`) ) ;

  }
}

and from Spring boot I've this

    package com.ayman.rest.webservices.restfulwebservices.todo;

    import java.net.URI;
    import java.sql.Date;
    import java.util.*;


    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.*;

    import org.springframework.web.servlet.support.ServletUriComponentsBuilder;



    import java.io.IOException;
    import javax.servlet.Filter;
    import javax.servlet.FilterChain;
    import javax.servlet.FilterConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;



    // -------- class for service ..........// 


    @CrossOrigin(origins = "http://localhost:4200" )
    @RestController
    public class todoResource {

        // injecting the static class so we can use the method findAll
        @Autowired
        private TodoHardcodedService todoService;


        //Display from server to frontend 
        @GetMapping("users/{username}/todo")
        public List<Todo> getAlltodo(@PathVariable String username) {

            return todoService.findAll();

        };



        // DELETE
        // user/{user_name}/todo/{todo-id}


        @DeleteMapping("users/username/todo/{id}")
        public ResponseEntity<Void> deleteTodo(@PathVariable String username, @PathVariable long id) {
            System.out.println("----------------------here we go--delete ---------------");
            Todo todo4 = todoService.deleteById(id);
            if (todo4 != null) {
                return ResponseEntity.noContent().build();
        }else{
            return ResponseEntity.notFound().build();
            }
        }











        //Display from server to frontend to be updated
        @GetMapping("users/{username}/todo/{id}")
        public Todo getTodo(@PathVariable String username, @PathVariable long id) {
            return todoService.findById(id);

        };


    //  update todo 
    //  Put user/{user_name}/todo/{todo-id}

        @PutMapping("users/{username}/todo/{id}")
        public ResponseEntity<Todo> updateTodo(
                @PathVariable String username, 
                @PathVariable long id ,
                @RequestBody Todo todo100) {


            Todo todoUpdated = this.todoService.save(todo100);

            return new ResponseEntity<Todo>(todo100, HttpStatus.OK);


            // or can just return todo100 and it will work fine.. 

            }

    //  create todo
    //  Post user/{user_name}/todo/


        @PostMapping("user/{user_name}/todo")
        public ResponseEntity<Void> updateTodo(
                @PathVariable String username, 
                @RequestBody Todo todo200) {

            Todo createdTodo = this.todoService.save(todo200);

            URI uri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(createdTodo.getId()).toUri();

            return ResponseEntity.created(uri).build();

            }


    }





    // ----------------- class todo ................//

    class Todo {

        protected Todo(){

        }




        private long id;
        private String username;
        private String description;
        private Date targetDate;
        private boolean isDone;

        public Todo(long id, String username, String description, Date targetDate, boolean isDone) {
            super();
            this.id = id;
            this.username = username;
            this.description = description;
            this.targetDate = targetDate;
            this.isDone = isDone;
        }

        public long getId() {
            return id;
        }

        public void setId(long id) {
            this.id = id;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getDescription() {
            return description;
        }

        public void setDescription(String description) {
            this.description = description;
        }

        public Date getTargetDate() {
            return targetDate;
        }

        public void setTargetDate(Date targetDate) {
            this.targetDate = targetDate;
        }

        public boolean isDone() {
            return isDone;
        }

        public void setDone(boolean isDone) {
            this.isDone = isDone;
        }

        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + (int) (id ^ (id >>> 32));
            return result;
        }

        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Todo other = (Todo) obj;
            if (id != other.id)
                return false;
            return true;
        }

    }

    // -------------class3
    @Service

    class TodoHardcodedService {
        private static List<Todo> todos1 = new ArrayList<Todo>();

        private static int counter = 1;

        static {
            todos1.add(new Todo(counter++, "aymanKO", "learn to dance", new Date(counter, counter, counter), false));
            todos1.add(new Todo(counter++, "Ranga", "learn to swim", new Date(counter, counter, counter), false));
            todos1.add(new Todo(counter++, "Araya", "learn to hunt", new Date(counter, counter, counter), false));
        }

        public List<Todo> findAll() {

            return todos1;
        }

        public Todo deleteById(long id) {
            Todo todo2 = findById(id);
            if (todo2 == null) {
                return null;
            }

            todos1.remove(todo2);
            return todo2;

        }

        public Todo findById(long id) {

            for (Todo todo3 : todos1) {
                if (todo3.getId() == id) {
                    return todo3;
                }
            }
            return null;
        }


        /// for the update save button 
        public Todo save(Todo todo60){

            // if there is no id or a record, then insert .. when equal to -1
            if( todo60.getId() == -1 || todo60.getId() == 0){
                todo60.setId(++counter);
                todos1.add(todo60);

            }else{
                // when having ID with values .. to update..
                // delete old one, and add the new record.
                deleteById(todo60.getId());
                todos1.add(todo60);
            }
            // return the new value..
            return todo60;

}

    }
Bill P
  • 3,622
  • 10
  • 20
  • 32
AAaaAA
  • 83
  • 11
  • https://stackoverflow.com/questions/36002493/no-access-control-allow-origin-header-in-angular-2-app check this link for access-control-allow-origin-header – Lingeshwaran Aug 21 '19 at 04:22
  • I think your CORS configuration is correct but get mapping is wrong. Change it to `@GetMapping("/users/{username}/todo")` (add slash before users) – Plochie Aug 21 '19 at 04:26
  • I tired but get works fine, it retrieve data from spring boot – AAaaAA Aug 21 '19 at 04:37
  • Refer this https://stackoverflow.com/questions/46788969/angular2-spring-boot-allow-cross-origin-on-put/46789290#46789290 – hrdkisback Aug 21 '19 at 05:01

5 Answers5

2

I'm so sorry guys after few hours of debugging, it turned out that I forgot to include

{username} the curly bracket on the username, so sorry silly solution for a silly error

the correct delete mapping is this

@DeleteMapping("users/{username}/todo/{id}")
AAaaAA
  • 83
  • 11
0

try something like this:

res.setHeader(
    "Access-Control-Allow-Methods",
    "GET, POST, PATCH, PUT, DELETE, OPTIONS"
  );
  • where can I add this ? – AAaaAA Aug 21 '19 at 04:37
  • this what I get when I use Restlet Client Extension "status": 405, "error": "Method Not Allowed", "message": "Request method 'DELETE' not supported", – AAaaAA Aug 21 '19 at 04:41
  • I Tried to Debug it, I added System.out.print inside the DeleteMapping method, but it won't invoke the request at all – AAaaAA Aug 21 '19 at 04:43
0

Register you configuration in CROS Config, put this inside the main class. Remove the @CrossOrigin from each class. It will work fine

@Bean
CorsConfigurationSource corsConfigurationSource() {
    CorsConfiguration configuration = new CorsConfiguration();
    configuration.setAllowedOrigins(Arrays.asList("http://localhost:4200"));
    configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "DELETE", "PUT", "PATCH"));
    configuration.setAllowedHeaders(Arrays.asList("X-Requested-With", "Origin", "Content-Type", "Accept","Authorization"));
    configuration.setAllowCredentials(true);
    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", configuration);
    return source;
}
varman
  • 8,704
  • 5
  • 19
  • 53
0

Here is what I would recommend doing on your frontend:

  • Add a file with the name proxy.config.json
{
  "*": {
    "target": "http://localhost:8080",
    "secure": false
  }
}
  • Start your local server like so ng serve proxy-config=proxy.config.json

Hope this helps.

Nephi
  • 103
  • 6
0

Create CORSFilter.java file in your project.

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter {

    /**
     * CORS filter for http-request and response
     */
    public CORSFilter() {
    }

    /**
     * Do Filter on every http-request.
     */
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Methods", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "content-type");

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }

    /**
     * Destroy method
     */
    @Override
    public void destroy() {
    }

    /**
     * Initialize CORS filter 
     */
    @Override
    public void init(FilterConfig arg0) throws ServletException {
    }
}
hrdkisback
  • 898
  • 8
  • 19