# Contact

IMPORTANT

  • Since version 9.35.x, Laravel uses a new syntax for sending emails (opens new window)
  • If you're using an older version, first update to the latest version with composer update
  • We'll use the integrated MailHog service to send (fake) mails in a development and testing environments
  • You can access the MailHog mailbox in the browser at http://localhost:8025 (or click on the @-icon in the footer menu)

Mailhog

  • The contact page contains some static content and a (dynamic) contact form
  • In web.php, we keep the route as a view route to resources/views/contact.blade.php and embed the Livewire component in that view

# Preparation

# Create a ContactForm component

  • Create a new Livewire ContactForm component with php artisan make:livewire ContactForm
    • app/Http/Livewire/Admin/ContactForm.php (the component class)
    • resources/views/livewire/admin/contact-form.blade.php (the component view)
  • Refactor the contact.blade.php view and embed the ContactForm component in it
  • The page contains some static content and embeds (on line 8) the ContactForm component




 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 


<x-vinylshop-layout>
    <x-slot name="description">Contact info</x-slot>
    <x-slot name="title">Contact info</x-slot>

    <div class="grid grid-cols-4 gap-4">
        <x-tmk.section class="col-span-4 lg:col-span-3 lg:order-2">
            {{-- embed the Livewire ContactForm component --}}
            @livewire('contact-form')
        </x-tmk.section>
        <section class="col-span-4 lg:col-span-1 lg:order-1">
            <h3>The Vinyl Shop</h3>
            <p>Kleinhoefstraat 4</p>
            <p class="pb-2 border-b">2440 Geel - Belgium</p>
            <p class="flex items-center pt-2 cursor-pointer">
                <x-phosphor-phone-call class="w-6 mr-2 text-gray-400"/>
                <a href="tel:+3214562310" class="mr-2">+32(0)14/56.23.10</a>
            </p>
            <p class="flex items-center pt-2 cursor-pointer">
                <x-heroicon-o-mail-open class="w-6 mr-2 text-gray-400"/>
                <a href="mailto:info@thevinylshop.com">info@thevinylshop.com</a>
            </p>
        </section>
    </div>
</x-vinylshop-layout>
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# Basic scaffolding

  • Open app/Http/Livewire/ContactForm.php and resources/views/livewire/contact-form.php
  • Line 4 - 6: the form has three input fields (name, email and message) so we need three public properties in the component
  • Line 12 - 15: the updated() method will be called every time a property is updated (so we can use it to validate the input in real time)
  • Line 18 -21: the form has a submit button, so we need a method for this sendEmail()
    • This method contains the validation and the sending of the email


 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 







class ContactForm extends Component
{
    // public properties
    public $name;
    public $email;
    public $message;
    
    // validation rules
    protected $rules = [];
    
    // real-time validation
    public function updated($propertyName, $propertyValue)
    {
        
    }
    
    // send email
    public function sendEmail()
    {
        
    }

    public function render()
    {
        return view('livewire.contact-form');
    }
}
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# Real-time form validation

  • Line 7 - 9: define the validation rules in the protected $rules array
    • The name field is required and must be at least 2 characters long
    • The email field is required and must be a valid email address
    • The message field is required and must be at least 10 characters long
  • Line 15: the updated() hook checks each updated input field individually against his validation rules
  • Line 22: you cannot pass this line until the validation is successful
  • Line 27 - 31: show a success message when the email is sent (send the actual mail will be covered soon)
  • Line 34: reset all public properties to their initial state






 
 
 





 






 




 
 
 
 
 


 





class ContactForm extends Component
{
    ...
    
    // validation rules
    protected $rules = [
        'name' => 'required|min:2',
        'email' => 'required|email',
        'message' => 'required|min:10',
    ];

    // real-time validation
    public function updated($propertyName, $propertyValue)
    {
        $this->validateOnly($propertyName);
    }

    // send email
    public function sendEmail()
    {
        // validate the whole request before sending the email
        $validatedData = $this->validate();

        // send email

        // show a success toast
        $this->dispatchBrowserEvent('swal:toast', [
            'background' => 'success',
            'html' => "<p class='font-bold mb-2'>Dear $this->name,</p>
                       <p>Thank you for your message.<br>We'll contact you as soon as possible.</p>",
        ]);

        // reset all public properties
        $this->reset();
    }

    public function render() { ... }
}
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# Disable the submit button

  • Remember that we modified the Jetstream button component a few chapters ago
    We added a disabled and the color attributes to the component
  • We can use the disabled attribute on the submit button to disable the button when the validation is not successful
  • Line 7: add a public property $can_submit with a default value of false
  • Line 15: set the $can_submit property to false if the full validation is successful
  • Line 17 - 18: set the $can_submit property to true if the name, email and message fields are not empty
    REMARK: the if() statement contains only rough validation (fields can not be empty). We don't check the length of the input fields, but that's enough for this example






 







 

 
 







class ContactForm extends Component
{
    // public properties
    public $name;
    public $email;
    public $message;
    public $can_submit = false;

    // validation rules
    protected $rules = [ ...];

    // real-time validation
    public function updated($propertyName, $propertyValue)
    {
        $this->can_submit = false;
        $this->validateOnly($propertyName);
        if ($this->name && $this->email && $this->contact && $this->message)
            $this->can_submit = true;
    }

    public function sendEmail() { ... }
    
    public function render() { ... }
}
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# Sending email

  • After configuring our mail settings, we set up a mail template, pass some data to this template and send the mail itself

# configure mail settings

  • The mail is already set up for you in the .env file
  • The .env file contains the following settings for the mail service:
    • Line 2: replace mailhog with localhost
    • Line 7: replace "hello@example.com" with your mailadres e.g. "info@vinyl_shop.test"

 




 


MAIL_MAILER=smtp
MAIL_HOST=localhost                        # replace 'mailhog' with 'localhost'
MAIL_PORT=1025
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="info@vinyl_shop.test"   # replace "hello@example.com" with your mailadres e.g. "info@vinyl_shop.test"
MAIL_FROM_NAME="${APP_NAME}"
Copied!
1
2
3
4
5
6
7
8

WARNINGS

  • If your variable contains spaces, surround it with quotes. E.g. MAIL_FROM_NAME="John Doe"
  • If you want a REAL email address to test certain functionalities, use Mailinator (opens new window) e.g. john.doe@mailinator.com.
    Emails sent to Mailinator are public but temporary and will disappear after a few hours.

# Create mailable

  • In Laravel, each type of email sent by your application is represented as a mailable (opens new window) class
  • Create a new mailable class with an associated view with the command:
    php artisan make:mail ContactMail --markdown=emails.contact-mail
    • The ContactMail mailable class is located in the app/Mail directory
    • The contact-mail view is located in the resources/views/emails directory
    • The --markdown option will create a markdown based view (opens new window)
      (Besides a Markdown-based mail template, used in this site, you can also opt for HTML or text-based templates for the mail)
php artisan make:mail ContactMail --markdown=emails.contact
Copied!
1

# Send your first email

  • Send an email inside the sendMail() method from our ContactForm component and open MailHog to see the result
  • Line 8: make a new variable $template of the ContactMail mailable class
  • Line 9: the variable $to contains the email address (first parameter) and the name (second parameter) of the person who receives the email
    (Import the class for the new Address: use Illuminate\Mail\Mailables\Address;!)
  • Line 10: add the recipient using the to() method (on the Mail facade)
  • Line 11: send the mail using the send() method with $template as parameter







 
 
 
 












// send email
public function sendEmail()
{
    // validate the whole request before sending the email
    $validatedData = $this->validate();

    // send email
    $template = new ContactMail();
    $to = new Address($this->email, $this->name);
    Mail::to($to)
        ->send($template);

    // show a success toast
    $this->dispatchBrowserEvent('swal:toast', [
        'background' => 'success',
        'html' => "<p class='font-bold mb-2'>Dear $this->name,</p>
                   <p>Thank you for your message.<br>We'll contact you as soon as possible.</p>",
    ]);

    // reset all public properties
    $this->reset();
}
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

REMARKS

  • You are not limited to theto() recipients. You can also add the cc() and bcc() recipients
  • All these methodes can handle multiple recipients with an array of recipients
  • The second parameter (the name) of the new Address() method is optional
  • If you don't need the name of the recipient, you can omit the new Address() and just pass the email address as a string,
    e.g. $to = 'john.doe@exmpale.com'; is the same as $to = new Address('john.doe@exmpale.com');
  • Example:


 
 
 
 
 
 


// send email
$template = new ContactMail();
$to_1 = new Address($this->email, $this->name);     // email + name
$to_2 = new Address('user2@example.com');           // email only
$to_3 = 'user3@example.com';                        // email only (same as above)
Mail::to([$to_1, $to_2, $to_3])
    ->cc(['user3@example.com', 'user4@example.com'])
    ->bcc(['user5@example.com', 'user6@example.com'])
    ->send($template);
Copied!
1
2
3
4
5
6
7
8
9
  • All other mail settings (subject, body, from, replayTo, ...) can be configured in the ContactMail class

# Pass data to the mailable and update the mail template

  • Add the data you want to use in the email as parameters to new ContactMail() to inject it into the constructor of mailable class and make it available in the mail template
    1. ContactForm component: add an array with the data you want to inject into the constructor of the mailable (and use in the mail template)
    2. ContactMail mailable: add a public property (e.g. $data) and assign the injected data via te constructor to it
    3. Update the Contact view and use the data from the mailable in the mail template
  • fromName and fromEmail will be used to override the default from address in the mailable class
  • subject will be used to override the default subject in the mailable class
  • name, email and message will be used in the body of the email



 
 
 
 
 
 
 
 





public function sendEmail()
{
    // send email
    $template = new ContactMail([
        'fromName' => 'The Vinyl Shop - Info',
        'fromEmail' => 'info@thevinylshop.com',
        'subject' => 'The Vinyl Shop - Contact Form',
        'name' => $this->name,
        'email' => $this->email,
        'message' => $this->message,
    ]);
    $to = new Address($this->email, $this->name);
    Mail::to($to)
        ->send($template);
}
Copied!
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Extra features

# Show error bag (optional)

  • Instead of showing each error message individually, we can show all errors in one single error block
  • To reuse the error block on different pages, we can best make a component for it
  • Create a new errorbag component inside the component's folder: resources/views/components/tmk/errorbag.blade.php
  • The component don't need extra properties or a slot because all the logic is inside the component itself
  • Add some extra code to the component:
  • Now we can re-use this component on every page where we want bundle the errors into a single error block
@if ($errors->any())
    <x-tmk.alert type="danger">
        <x-tmk.list>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </x-tmk.list>
    </x-tmk.alert>
@endif
Copied!
1
2
3
4
5
6
7
8
9

# EXERCISE: Add a contact field to the form

  • Add a dropdown list to the form in order to choose a specific contact
  • The list contains four options: Select a contact (value=""), Info, Billing and Support
  • This is a required field, so add it to your validation
  • Depending on the choice of the user, the from (and carbon copy) address should be adjusted:
    • info@thevinylshop.com with the name The Vinyl Shop - Info
    • billing@thevinylshop.com with the name The Vinyl Shop - Billing
    • or support@thevinylshop.com with the name The Vinyl Shop - Support

exercise form

Last Updated: 5/4/2023, 2:27:29 PM