Dodanie inputa dla podobiektu

0

Cześć,

Stworzyłem w Springu backened do prostej apki. Teraz chce dorobić do niej front w Angularze i napotkałem następujący problem:

  1. W backendzie używam relacji @OneToMany i obsługuję metodę POST, którą przyjmuje w postmanie następujący request.

    {
            "id": 1,
            "taskName": "Creating models",
            "description": "developing models of data",
            "taskDate": "2022-12-17T11:00:00",
            "group": {
                "id": 4,
                "taskGroupName": "Programming"
            },
            "done": false
        }
    
    
  2. Teraz chcę w Angularze zrobić input i za pomocą metody POST wysłać dane do backendu. Wszystkie podstawowe pola działają prawidłowo, jednak w przypadku group dostaję błąd. Zdefiniowałem sobie w Angularze model danych:

    export interface Task {
      id: number;
      taskName: String;
      description: String;
      isDone: boolean;
      taskDate: Timestamp<any>;
      group: {
        id: number;
        taskGroupName: String;
      };
    
    
  3. Chcę zrobić Input w postaci dla wszystkich pól (tutaj wrzucam tylko dla id grupy, bo konkretnie to mi nie działa):

    <input type="text" ngModel="{{modelAdd.group.id}}" name="group.id" class="form-control" id="inputgroupb2" aria-describedby="title" placeholder="taskgroupId">
    

    Jednak dostaję błąd, że group.id jest 'undefined'.
    Dlaczego nie mogę w ten sposób pobrać danych w postaci inputa. Dodam tylko, że w analogiczny sposób metoda GET pozwala mi na wyświetlanie danych związanych z grupą:

    <div *ngFor="let task of tasks">
      <div>{{task.id}} {{task.taskName}} {{task.taskDate}} {{task.isDone}}  {{task.group.id}} {{task.group.taskGroupName}}</div>
    </div>
    

    i działa to poprawnie.

  4. Kod w szablonie wygląda mniej więcej tak:

    <button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
       Launch demo modal
     </button>
    
    <!--  MODAL WINDOW ADD-->
     <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
       <div class="modal-dialog" role="document">
         <div class="modal-content">
           <div class="modal-header">
             <form #addForm="ngForm">
               <h5 class="modal-title" id="exampleModalLabel">Edit task group with Id: <b>{{modelAdd.id}}</b></h5>
               <div class="form-group">
    <!--              <label for="inputTaskName2"></label>-->
                 <input type="text" ngModel="{{modelAdd.taskName}}" name="taskName" class="form-control" id="inputTaskName2" aria-describedby="title" placeholder="Task name">
    <!--              <input type="text" ngModel="{{modelAdd.taskDate}}" name="taskDate" class="form-control" id="inputTaskDate2" aria-describedby="title" placeholder="Task date">-->
                 <input type="text" ngModel="{{modelAdd?.group.id}}" name="group.id" class="form-control" id="inputgroupb2" aria-describedby="title" placeholder="taskgroupId">
    <!--              <input type="text" ngModel="{{modelAdd.group?.taskGroupName}}" name="taskGroupName" class="form-control" id="inputgroupa2" aria-describedby="title" placeholder="taskGroupName">-->
    <!--              <input type="text" ngModel="{{modelAdd.description}}" name="description" class="form-control" id="inputTaskdescription2" aria-describedby="title" placeholder="Task description">-->
    <!--              <input class="form-control" name="id" ngModel="{{modelAdd.id}}" id="id" [defaultValue]="modelAdd.id" type="hidden">-->
               </div>
               <div class="modal-footer">
                 <button type="button" id="" data-dismiss="modal" class="btn btn-secondary">Close</button>
                 <button (click)="onAddTask(addForm.value)" data-dismiss="modal" class="btn btn-primary" >Save changes</button>
               </div>
             </form>
           </div>
         </div>
       </div>
     </div>
    
  5. Jak za pomocą takich inputów pobrać dane od użytkownika i stworzyć następujący request: (pola id, taskname, description, taskDate, done działają poprawnie jak to zrobię w ten sposób, pola związane z group już są undefined tak jakby ich nie dostawał). Co robię źlę? Jak zrobić to poprawnie? Chodzi o to, że ngModel="{{modelAdd.description}}" działa, ale już ngModel="{{modelAdd.group.id}}" dla mojego modelu danych nie działa.

    {
         "id": 1,
         "taskName": "Creating models",
         "description": "developing models of data",
         "taskDate": "2022-12-17T11:00:00",
         "group": {
             "id": 4,
             "taskGroupName": "Programming"
         },
         "done": false
     }
    
0

Jak dostajesz odpowiedź z backendu to masz prawidłowo utworzony obiekt JSON i pole group automatycznie ci się zmapuje na obiekt. Jak robisz formularz dodawania to musisz go sobie sam odpowiednio utworzyć, a na defaulcie pole group zainicjuje się wartością undefined.
Pokaż czym jest modelAdd i jak go inicjalizujesz

0
FrontendGuy napisał(a):

Jak dostajesz odpowiedź z backendu to masz prawidłowo utworzony obiekt JSON i pole group automatycznie ci się zmapuje na obiekt. Jak robisz formularz dodawania to musisz go sobie sam odpowiednio utworzyć, a na defaulcie pole group zainicjuje się wartością undefined.
Pokaż czym jest modelAdd i jak go inicjalizujesz

Mam pliku .ts dla tego komponentu mam to zdefiniowane tak:

 modelAdd: Partial<Task> = {};

Korzysta z tego metoda, która odwołuje się do serwisu, w którym mam obsługę wszystkich metod HTTP

 onAddTask(addFrom: Partial<Task>)
  {   
     this.http.postTasks(this.modelAdd as Task).subscribe((response: Task) => {this.getTaskwithDate()})
  }

AD 1. No i tak, rozumiem o co chodzi. Potrafię zrobić formularz dla prostego obiektu, gdzie w pierwotnej tabeli nie ma żadnych relacji/odwołań do innych obiektów tylko proste pola do uzupełnienia.

Wtedy robię to prostym inputem:

<input type="text" ngModel="{{modelAdd.taskName}}" name="taskName" class="form-control" id="inputTaskName2" aria-describedby="title" placeholder="Task name">

Ale nie bardzo wiem, jak powinien wyglądać input dla takiej struktury:

export interface Task {
  id: number;
  taskName: String;
  description: String;
  isDone: boolean;
  taskDate: Timestamp<any>;
  group: {
    id: number;
    taskGroupName: String;
  };

Pola id, taskName, description, isDone, taskDate mogę dodać formularzem z inputami jak pkt AD1.
Ale jak powinien wyglądać input w formularzu (co ma być w ngModel={{}} i name="", bo te dwa pola sa tutaj najważniejsze), żeby uzupełnić pola id, taskGrupName?
To co zaproponowałem w pierwszym poście nie działa i nie bardzo wiem dlaczego: ngModel="{{modelAdd?.group.id}}" name="group.id".
Jak dla mnie to cała metoda itd działa dobrze, problem jest w tym, że nie wiem jak zrobić poprawnie input'y w formularzu dla tych dwóch pól.
Proszę o pomoc, jak ktoś ma jakiś pomysł, bo już trochę nie wiem jak to ruszyć.

1

Zamień sobie:

modelAdd: Partial<Task> = {};

na

modelAdd: Partial<Task> = {
     "id": 1,
     "taskName": "Creating models",
     "description": "developing models of data",
     "taskDate": "2022-12-17T11:00:00",
     "group": {
         "id": 4,
         "taskGroupName": "Programming"
     },
     "done": false
 }

i zobacz rezultat.
Liczę, że to Cię naprowadzi :)

0

Cześć,

@FrontendGuy: Dzięki, trochę mi to zajęło, ale w końcu zrobiłem tak jak napisałeś i udało mi się rozwiązać problem.
Nie wiem czy to jest zgodnie ze sztuką, ale zamiast korzystać bezpośrednio z modelu Task, zadeklarowałem:

group: {id: number, taskGroupName: String} = {id: 1, taskGroupName: "random"};

i zrobiłem inputy, który przypisuje wartości do tego:

 <input type="text" [(ngModel)]="group.id" class="form-control" name="group.id" placeholder="taskgroupId">
 <input type="text" [(ngModel)]="group.taskGroupName" class="form-control" name="taskGroupName" placeholder="taskGroupName">

i na końcu, już w metodzie przypisałem zapodane w inpucie wartości do mojego modelu Taska:

this.modelAdd.group = {id: this.group.id, taskGroupName: this.group.taskGroupName};

Działa ! :-)

Tylko skoro już lepiej lub gorzej udało mi się rozwiązać problem. Mógłbyś mi wyjaśnić jakoś teoretycznie dlaczego to wcześniej nie działało?
No, bo rozumiem, że jak się poda tylko ID, albo tylko taskGroupName to to nie zadziała rzeczywiście. Ja podawałem tylko jedną z tych wartości.

Ale nadal nie rozumiem dlaczego mogłem zrobić coś takiego i to działało (dostawałem id grupy dla modelu Taska):

<div *ngFor="let task of tasks">
  <div>{{task.group.id}}</div>
</div>

Ale przypisanie wartości w inpucie już nie działało i dawało mi wartość undefined:

<input type="text" ngModel="{{modelAdd.group.id}}" name="group.id" class="form-control" id="inputgroupb2" aria-describedby="title" placeholder="taskgroupId">


Jakie jest teoretyczne wyjaśnienie tego, bo niby zrobiłem, działa. Coś tam "świta", ale jakby mnie ktoś spytał, żebym własnymi słowami wyjaśnił czemu powyższe nie działa to taki na 100% bym nie był pewien co mu odpowiedzieć?

0

Fajnie, że się udało :)

Odpowiedź z serwera zawierała już obiekt group z polami id i taskGroupName natomiast podczas dodawania SAM tworzyłeś sobie model, który miał niezdefiniowane pole 'group'.

Odpowiedź z serwera:

modelAdd: Partial<Task> = {
     "id": 1,
     "taskName": "Creating models",
     "description": "developing models of data",
     "taskDate": "2022-12-17T11:00:00",
     "group": {
         "id": 4,
         "taskGroupName": "Programming"
     },
     "done": false
 }

masz tam pole group:

"group": {
         "id": 4,
         "taskGroupName": "Programming"
     }

Twój model podczas dodawania:

modelAdd: Partial<Task> = {};

Twoje pole 'group' = undefined

1 użytkowników online, w tym zalogowanych: 0, gości: 1