orchidsoftware / platform

Orchid is a @laravel package that allows for rapid application development of back-office applications, admin/user panels, and dashboards.
https://orchid.software
MIT License
4.26k stars 631 forks source link

Action "change->form#changed" references undefined method "changed" #2705

Closed EeKay closed 9 months ago

EeKay commented 10 months ago

Describe the bug After upgrading my project to Laravel 10 and Orchid 14 (14.9.1), following the upgrade guide, I tested and the screens are all displayed nicely etc.

My forms now seem to be broken as the JS tries to invoke event functions that aren't found?

ie: when i change a value on an input, and move the focus to another field i get:

[Error] Error invoking action "change->form#changed"

Error: Action "change->form#changed" references undefined method "changed" — orchid.js:2:5804

Object
controller: e {context: _}
element: <form id="post-form">
event: Event {isTrusted: true, immediatePropagationStopped: false, stopImmediatePropagation: function, params: {}, type: "change", …}
identifier: "form"
index: 3

Object Prototype
    handleError (orchid.js:2:36779)
    handleError (orchid.js:2:25476)
    invokeWithEvent (orchid.js:2:6523)
    handleEvent (orchid.js:2:5653)
    handleEvent (orchid.js:2:844)

breakpoint in the orchid.js's "handleError" function on line 1917 gives me:

message: "Action \"change->form#changed\" references undefined method \"changed\""
sourceURL: "http://woordenschat.test/vendor/orchid/js/orchid.js"
stack: "method@http://woordenschat.test/vendor/orchid/js/orchid.js:2:5803↵invokeWithEvent@http://woordenschat.test/vendor/orchid/js/orchid.js:2:6240…"

To Reproduce Steps to reproduce the behavior:

  1. Upgraded project to Laravel 10 and Orchid 14.9.1
  2. Follow the upgrade guide
  3. Ran composer and npm run dev and cleaned config, routes and cache
  4. On local testversion, I go to a screen with a form, edit the input field value, press tab

Expected behavior I'd expect no JS value, the event js being called properly to handle updates, and being able to "save" the info. I get a JS error and the save (and delete buttons etc dont work because of this).

Screenshots If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

Server (please complete the following information):

Additional context Add any other context about the problem here.

EeKay commented 10 months ago

@tabuna: I suspect this might be a small thing to fix (probably configuration or such, but can't seem to find out what).

Tried adding jQuery to the config, imagining the form events js needed this somehow. Hope you recognize this and/or might know where to look...

Here's one screen definition (they all go wrong):

<?php

namespace App\Orchid\Screens;

use App\Models\Periode;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
use Orchid\Platform\Models\Role;
use Orchid\Screen\Fields\Input;
use Orchid\Screen\Fields\Select;
use Orchid\Screen\Fields\DateTimer;
use Orchid\Screen\Fields\Relation;
use Orchid\Screen\Fields\TextArea;
use Orchid\Screen\Fields\Upload;
use Orchid\Support\Facades\Layout;
use Orchid\Screen\Actions\Button;
use Orchid\Screen\Fields\Label;
use Orchid\Screen\Screen;
use Orchid\Support\Facades\Alert;

class PeriodeEditScreen extends Screen
{
    /**
     * Display header name.
     *
     * @var string
     */
    public $name = 'Periode toevoegen';

    /**
     * Display header description.
     *
     * @var string|null
     */
    public $description = 'Periodes';

    /**
     * @var bool
     */
    public $exists = false;

    /**
     * @var int
     */
    private $authid;

    /**
     * @var Periode
     */
    private $currentPeriode;

    /**
     * Query data.
     * @param Periode    $periode
     * @return array
     */
    public function query(Periode $periode): array
    {
        $this->exists = $periode->exists;
        $this->authid = Auth::id();

        if($this->exists){
            $this->currentPeriode = $periode;
            $this->name = 'Periode wijzigen';
        }

        return [
            'periode' => $periode
        ];
    }

    /**
     * Button commands.
     *
     * @return \Orchid\Screen\Action[]
     */
    public function commandBar(): array
    {
        return [
            Button::make('Opslaan')
                ->icon('pencil')
                ->method('createOrUpdate')
                ->canSee(!$this->exists),

            Button::make('Wijzigen')
                ->icon('note')
                ->method('createOrUpdate')
                ->canSee($this->exists),

            Button::make('Verwijderen')
                ->icon('trash')
                ->method('remove')
                ->canSee($this->exists),
        ];
    }

    /**
     * Views.
     *
     * @return \Orchid\Screen\Layout[]|string[]
     */
    public function layout(): array
    {
        return [
            Layout::rows([

                Input::make('periode.weergave_naam')
                    ->title('Weergave naam')
                    ->canSee($this->exists)
                    ->readonly(),

                Input::make('periode.jaar')
                    ->title('Jaar')
                    ->type('number')
                    ->placeholder(date("Y").', ...')
                    ->required()
                    ->help('Voor welk jaar (het beginjaar van jaar) is deze periode?')
                    ->popover('Voor welk jaar (het beginjaar van jaar) is deze periode? Voor jaar 2021-2022 vul je bijvoorbeeld in dit veld 2021 in'),

                Input::make('periode.periode_nummer')
                    ->title('Periodenummer')
                    ->type('number')
                    ->required()
                    ->placeholder('1, 2, ...')
                    ->help('De hoeveelste periode van het jaar is dit?'),

                DateTimer::make('periode.begindatum')
                    ->title('Begindatum')
                    ->type('date')
                    ->required()
                    ->format('Y-m-d')
                    ->help('De begindatum van de periode'),

                DateTimer::make('periode.einddatum')
                    ->title('Einddatum')
                    ->type('date')
                    ->required()
                    ->format('Y-m-d')
                    ->help('De einddatum van de periode'),
            ]),
            Layout::accordion([
                'Bewerking details' => [
                    Layout::rows([

                        Input::make('periode.creatornaam')
                            ->title('Aangemaakt door')
                            ->value($this->exists ? User::where('id', $this->currentPeriode->creator_id)->first()->name : '')
                            ->canSee($this->exists)
                            ->readonly(),

                        Input::make('periode.created_at')
                            ->title('Aangemaakt')
                            ->canSee($this->exists)
                            ->readonly(),

                        Input::make('periode.updated_at')
                            ->title('Laatst gewijzigd')
                            ->canSee($this->exists)
                            ->readonly(),
                    ]),
                ],
            ])
            ->canSee($this->exists),
        ];
    }

    /**
     * @param Periode    $periode
     * @param Request $request
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function createOrUpdate(Periode $periode, Request $request)
    {
        $this->exists = $periode->exists;
        $this->authid = Auth::id();
        dd('test');
        if(!$this->exists)
        {
            $periode->fill($request->get('periode'));
            $periode['creator_id'] = $this->authid;
            $periode['weergave_naam'] = $this->createWeergaveNaam($periode);
            $passed = $this->CheckConstraints($periode);
            $periode->save();
            Alert::success('Je hebt de periode succesvol aangemaakt');
            return redirect()->route('platform.periode.list');
        } else {
            $periode->fill($request->get('periode'));
            $passed = $this->CheckConstraints($periode);
            $changesMade = $periode->isDirty();
            if ($changesMade)
            {
                $periode['weergave_naam'] = $this->createWeergaveNaam($periode);
                $periode['updater_id'] = $this->authid;
                Alert::success('Je hebt de periode succesvol gewijzigd');
            }
            $periode->update();
            return Redirect::back();
        }
    }

    /**
     * Creates the display name of the period defined by year and period number
     */
    private function createWeergaveNaam(Periode $periode)
    {
        return __('Periode').' '.$periode->jaar.'-'.$periode->periode_nummer;
    }

    //todo: add validation to createOrUpdate function and use custom rules
    // validation   : https://laravel.com/docs/8.x/validation#validation-quickstart
    // custom rules : https://web-tuts.com/laravel-8-custom-validation-rules-example/
    private function CheckConstraints(Periode $periode)
    {
        //check if number of period is ascending next one for the year
        $periods_in_year = Periode::where('jaar', $periode->jaar);
        $biggest_period_number = $periods_in_year->max('periode_nummer');
        $isascendingnumber = ($periode->periode_nummer == $biggest_period_number + 1);

        //check if period for year not already added
        $periodforyearalreadyexists = ($periods_in_year->where('periode_nummer', $periode->periode_nummer)->count() > 0);

        //check if period date is
        return $isascendingnumber && !$periodforyearalreadyexists;
    }

    /**
     * @param Periode $periode
     *
     * @return \Illuminate\Http\RedirectResponse
     * @throws \Exception
     */
    public function remove(Periode $periode)
    {
        $periode->delete();

        Alert::success('Je hebt de periode succesvol verwijderd.');

        return redirect()->route('platform.periode.list');
    }
}
tabuna commented 10 months ago

Hi @EeKay! The function you're looking for is actually present in the provided files:

You can find it here: form_controller.js

To ensure that you have the most up-to-date resources, make sure to run the following command:

php artisan orchid:publish

I highly recommend adding this command to your composer file so that it can be executed automatically.

For more information, you can refer to the documentation here.

EeKay commented 9 months ago

Thanks I indeed forgot to re publish orchid to get the js in order 🙏🏻