Brad Ahrens
Brad Ahrens

Reputation: 5168

Can't pass hidden input value from Angular to PHP

I have created a form in which I would like users to select the room that they want, among other things. If I do this as a dropdown or as an input type in which they type in the information, it is submitted via email through PHP.

However, if I change the input type to "hidden", the value completely disappears and what I see in the console is this:

<input _ngcontent-c4 name="room" type="hidden" value class="ng-untouched ng-pristine ng-valid">

Then, in the Network, nothing appears as an object for "room". (Note: other objects do appear.)

Then, if I simply change the style to "display: none;" and put the value="ChosenRoom", nothing is sent in the email. In fact, despite showing up clearly in the console as

<input _ngcontent-c4 name="room" style="display: none;" type="text" value="ChosenRoom" class="ng-untouched ng-pristine ng-valid">

the object doesn't show up in the network.

Any idea what could be the problem?

CODE:

(I have posted it in a rudimentary Plunker as well: http://embed.plnkr.co/uUhPrStdw4kDhaus2xfO/)

This one works, but the user has to type in the room name in the form:

HTML (Note: I left out the remaining code for the form, assuming that it isn't relevant in this case. If you think this would help, I'd be happy to post that as well.)

<form (submit)="sendEmail(message)" #f="ngForm">
    <input type="text" name="room" [(ngModel)]="message.room" #room="ngModel">
    <button type="submit" [disabled]="f.invalid" *ngIf="!f.submitted">
</form>

HTML - This one doesn't show the value in the console.

<form (submit)="sendEmail(message)" #f="ngForm">
    <input type="hidden" name="room" [(ngModel)]="message.room" #room="ngModel" value="ThisRoom">
    <button type="submit" [disabled]="f.invalid" *ngIf="!f.submitted">
</form>

HTML - This one shows the value in the console, but does not show any object in the Network.

<form (submit)="sendEmail(message)" #f="ngForm">
    <input type="text" style="display: none;" name="room" [(ngModel)]="message.room" #room="ngModel" value="ThisRoom">
    <button type="submit" [disabled]="f.invalid" *ngIf="!f.submitted">
</form>

Typescript: Contact.Service.TS

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import { Resolve } from '@angular/router';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

export interface IMessage {
  name?: string,
  email?: string,
  room?: string,
  daterange?: string,
  message?: string
}

@Injectable()
export class AppService {
  private emailUrl = '/assets/email.php';

  constructor(private http: Http) {

  }

  sendEmail(message: IMessage): Observable<IMessage> | any {
    return this.http.post(this.emailUrl, message)
      .map(response => {
        console.log('Sending email was successfull', response);
        return response;
      })
      .catch(error => {
        console.log('Sending email got error', error);
        return Observable.throw(error)
      })
  }
}

PHP

<?php

header('Content-type: application/json');

$errors = '';

if(empty($errors))
{

    $postdata = file_get_contents("php://input");
    $request = json_decode($postdata);


    $from_email = '[email protected]';
    $message = $request->message;
    $from_name = $request->name;

    $to_email = "[email protected]";

    $contact = "<p><strong>Name:</strong> $from_name</p>
                <p><strong>Email:</strong> $request->email</p>
                <p><strong>Room:</strong> $request->room</p>
                <p><strong>Dates:</strong> $request->daterange</p>";
    $content = "<p><strong>Message:</strong><p>$message</p>";




    $website = 'My Currently Not but soon to be Functioning Website';
    $email_subject = "$website: Received a message from $from_name";

    $email_body = '<html><body>';
    $email_body .= "$contact $content";
    $email_body .= '</body></html>';

    $headers .= "MIME-Version: 1.0\r\n";
    $headers .= "Content-Type: text/html; charset=ISO-8859-1\r\n";
    $headers .= "From: $from_email\n";
    $headers .= "Reply-To: $from_email";

    $result = mail($to_email,$email_subject,$email_body,$headers);

    $response_array['status'] = 'success';
    $response_array['from'] = $from_email;
    $response_array['result'] = $result;

    echo json_encode($response_array);

    header($response_array);
    return $from_email;
} else {
    $response_array['status'] = 'error';
    echo json_encode($response_array);
    header('Location: /error.html');
}
?>

I appreciate any help or ideas.

Thanks!

Brad

Upvotes: 0

Views: 1390

Answers (2)

AVJT82
AVJT82

Reputation: 73367

First of all, that the value is not added, is because ngModel overrides value and therefore has nothing to do with the fact that is hidden. Secondly I would suggest that you might want to use a model-driven form here. Sometimes a model-driven form is overkill, but in this case I'd use one. So I'd thought I'd throw in that option for you, if you want to consider it.

You need to import ReactiveFormsModule and add it to your imports array in your ngModule. Then import the following to your component and inject FormBuilder in your constructor:

import { FormBuilder, FormGroup, Validators } from '@angular/forms';

constructor(private fb: FormBuilder) {}

Then build the form with the validators you want:

this.myForm = this.fb.group({
  room: ['theEnsuite'],
  name: ['', Validators.required],
  email: ['', [Validators.required, Validators.pattern('[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,3}$']],
  message: ['', [Validators.required, Validators.minLength(10)]]
})

and then you can get rid of the two-way binding and exchange it with form control instead. The good thing is, that you do not need to include the room at all in your template. It is nicely already sitting in the form object :) Here's a sample of the name input with error message:

<input placeholder="Name" formControlName="name">
<div *ngIf="!myForm.get('name').valid && myForm.get('name').touched">
  <p>Please enter your name.</p>
</div>

When you submit the form you do it with myForm.value as parameter. That object then is identical to your object of type IMessage, which you can use the post request directly with this object!

Here's a DEMO of the above.

Upvotes: 0

Brad Ahrens
Brad Ahrens

Reputation: 5168

I have found one solution for this problem. It completely avoids the hidden fields, which I'm still not sure if they were the problem or not.

Working Solution:

contact.component.html - Here, I avoid the hidden input and pass the text beside the message. Pay special attention to 'This particular room'

<form (submit)="sendEmail(message, 'This particular room')" #f="ngForm">
...
</form>

contact.component.ts - Pay special attention to message.room = room;

import { Component, OnInit, HostBinding } from '@angular/core';
import { AppService, IMessage } from '../../contact/contact.service';

@Component({
  selector: 'app-contact',
  templateUrl: './contact.component.html',
  styleUrls: ['./contact.component.css']
})
export class TheensuiteComponent implements OnInit {
    message: IMessage = {};

  constructor(private appService: AppService) { }

  sendEmail(message: IMessage, room:string) {
    message.room = room;
    this.appService.sendEmail(message).subscribe(res => {
      console.log('ContactComponent Success', res);
    }, error => {
      console.log('ContactComponent Error', error);
    })
  }

  ngOnInit() {
    };
  }
}

Everything else is left the same (contact.service.ts and email.php).

This is, of course, a slight hack. If I wanted to pass more information, this could cause jumbled code pretty quickly.

Upvotes: 1

Related Questions