Search code examples
angularrestspring-data-resthateoasspring-hateoas

Angular 4 update nested field


Having trouble with updating my model using @angular/http method http.put().

The issue is that I just can't update Position at all. I can successfully update any other field and can set any Position when creating with POST.

My angular version is "^4.3.3"

In java my model looks like

public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long id;

    String name;

    String email;

    String phone;

    Date birthDay;

    @JsonBackReference
    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "position_id")
    Position position;
}

Projection:

public interface EmployeeProjection {

    Long getId();

    String getName();

    String getEmail();

    String getPhone();

    Date getBirthDay();

    @Value("#{target.position.name}")
    String getPosition();
}

And Position class:

public class Position {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long id;

    String name;
}

In angular template Position:

<md-select mdInput placeholder="Position"
           [(ngModel)]="newEmployee.position">
  <md-option *ngFor="let position of positions | async" [value]="position.name">{{ position.name }}
   </md-option>
</md-select>

My update method in component:

update() {
    let positionName = this.employee.position;
    this.positionService.findByName(positionName).subscribe(position => {
      this.employee.position = position._links.self.href;
      this.employeeService.update(this.employee);
      this.employee.position = positionName;
      this.employeeService.localStorageService.set('employee', this.employee);
    });
  }

And in service:

update(employee: Employee) {
    this.http.put(employee._links.self.href, employee)
      .map((resp: Response) => resp.json())
      .subscribe(() => {
        this.getAll();
      });
    return employee;
  }

In chrome Request:

{
  "name": "Nikolai Morgan",
  "id": 1,
  "position": "http://localhost:9080/api/positions/5",
  "birthDay": "1986-07-01",
  "email": "NikolaiMorgan@gmail.com",
  "phone": "+380840713229",
  "_links": {
    "self": {
      "href": "http://localhost:9080/api/employees/1"
    },
    "employee": {
      "href": "http://localhost:9080/api/employees/1{?projection}",
      "templated": true
    },
    "position": {
      "href": "http://localhost:9080/api/employees/1/position"
    }
  }
}

But response and preview not contain field Position:

{
  "id" : 1,
  "name" : "Nikolai Morgan",
  "email" : "NikolaiMorgan@gmail.com",
  "phone" : "+380840713229",
  "birthDay" : "1986-07-01",
  "_links" : {
    "self" : {
      "href" : "http://localhost:9080/api/employees/1"
    },
    "employee" : {
      "href" : "http://localhost:9080/api/employees/1{?projection}",
      "templated" : true
    },
    "position" : {
      "href" : "http://localhost:9080/api/employees/1/position"
    }
  }
}

Solution

  • To update entity that has reference to another one, in Spring Data REST you have to use a link to this entity. For example:

    @Entity
    class Employee {
        //...
    
        String name;
    
        @ManyToOne
        Position position;   
    
        //...
    }
    
    @Entity
    class Position {
        //...
    
        String name;
    
        //...
    }
    
    interface EmployeeRepo extends JpaRepository<Employee, Long> {}
    interface PositionRepo extends JpaRepository<Position, Long> {}
    

    First we add a position:

    POST http://localhost:9080/api/positions

    {
        "name": "position1"
    }
    

    And get a response like this:

    {
        "name": "position1",
        "_links" : {
            "self" : {
              "href" : "http://localhost:9080/api/positions/1"
            },
            "position" : {
              "href" : "http://localhost:9080/api/positions/1"
            }
        }
    }
    

    Then add an employee:

    POST http://localhost:9080/api/employees

    {
        "name": "employee1",
        "employee": "http://localhost:9080/api/positions/1"
    }
    

    Then get a response:

    {
      "name" : "employee1",
      "_links" : {
        "self" : {
          "href" : "http://localhost:9080/api/employees/1"
        },
        "employee" : {
          "href" : "http://localhost:9080/api/employees/1",
        },
        "position" : {
          "href" : "http://localhost:9080/api/employees/1/position"
        }
      }
    }
    

    So if we need to update position we create a new one, then PUT the employee:

    PUT http://localhost:9080/api/employees/1

    {
        "name": "employee1", 
        "position": "http://localhost:9080/api/positions/2"
    }
    

    Or even PATCH it:

    PATCH http://localhost:9080/api/employees/1

    {
        "position": "http://localhost:9080/api/positions/2"
    }