0

This is an updated version of my original question. I created a feedback form (ff) with a text input and file input, binded with [(ngModel)]="feedback.message" & "feedback.screenshot".

The console gives me this error "JSON.parse: unexpected end of data at line 1 column 1 of the JSON data" either from ff-service or the ff-form component file.

My form:

<form #f="ngForm" (ngSubmit)="onSubmit(f.value)" >

            <div class="modal-body">
                <p class="lead-text"><strong>Bel ons</strong> op </p>
                <p><em>of</em></p>

                    <div class="form-group">
                        <label for="message">Verzend bericht</label>
                        <textarea class="form-control" required [(ngModel)]="feedback.message" name="message" #message="ngModel" placeholder="Beschrijf uw vraag, feedback of idee" rows="3" ></textarea>
                        <div [hidden]="message.valid || message.pristine" class="alert alert-danger">
                            Geef aub een beschrijving
                        </div>
                        <label for="screenshot">Schermafbeelding toevoegen</label>
                        <input type="file" [(ngModel)]="feedback.screenshot" name="screenshot" #screenshot="ngModel">
                    </div>

            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-default" data-dismiss="modal">Annuleren</button>
                <button type="submit" class="btn btn-default" [disabled]="!f.form.valid" >Verzenden</button>
            </div>

        </form>

Here's my component file.

import { Component, OnInit }    from '@angular/core';
import { NgForm }               from '@angular/common';

import { Feedback }             from './feedback';
import { FormService }          from './feedback-form.service';

@Component({
    selector: 'feedback-form',
    templateUrl: 'app/feedback-form.component.html',
    providers: [FormService]
})

export class FeedbackFormComponent implements OnInit {
    response: string;
    value: string;

    constructor(private _formService : FormService){  }

    public feedback: Feedback; 

    ngOnInit(){
        //initialize form
        this.feedback = {
            message: '',
            screenshot: ''
        }
    }

    submitted = false;

    onSubmit(form: Feedback) { 
        this._formService.sendMail(form)
            .subscribe(
                response => this.response = response,
                error => console.log(error)
            )
        this.submitted = true;
    }


    //TODO remove when we are done 
    get diagnostic(){
        return JSON.stringify(this.feedback);
    }
}

//https://angular.io/docs/ts/latest/guide/forms.html

my form.service.ts file:

    import { Injectable }                               from '@angular/core';
import { Http, Response, Headers, RequestOptions, URLSearchParams }  from '@angular/http';
import { Observable }                               from 'rxjs/Observable';

@Injectable()

export class FormService {
    constructor(private _http: Http) {  
       }
    private _mailUrl = 'http://app/form-mailer.php';

    sendMail(value: any): Observable<any> {
        const body = new URLSearchParams(value);
        body.set('message',value.message);
        body.set('screenshot',value.screenshot);


        let headers = new Headers();
        headers.append('Content-Type','application/x-www-form-urlencoded');
        headers.append('Accept','application/json');
        //headers.append('Access-Control-Allow-Origin','*');
        return this._http.post(this._mailUrl, body.toString(), { headers: headers })
            .map(res => {
                res.json();
                console.log();
            })
            .catch(this.handleError)
    }

    private handleError (error: any) {
        // In a real world app, we might use a remote logging infrastructure
        let errMsg = (error.message) ? error.message :
        error.status ? `${error.status} - ${error.statusText}` : 'Server error';
        console.error(errMsg); // log to console instead
        return Observable.throw(errMsg);
    }
}

server side php code:

<?php 
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Headers: X-Requested-With');
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Content-Type: application/json');

error_reporting(0);

$formData = json_decode(file_get_contents('php://input'));
foreach ($formData as $key=>$value) {
        $_POST[$key]=$value;
    }

$formMsg            = $_POST['message'];
$formScreenshot     = $_POST['screenshot'];

$msg = "Message:\n $formMsg\n Screenshot:\n $formScreenshot";
mail('info@bla.be','Feedback',$msg);
echo json_encode($formData); 
?>

Thanks for your help! Fred

Fred30
  • 89
  • 1
  • 2
  • 11

1 Answers1

0

UPDATE 2

I am going to start by breaking down the issues that I see in your form.service.ts file.

  1. Your passing a Javascript object into URLSearchParams constructor when it actually expects a string. I'm not really sure why this isn't already causing TypeScript to throw an error.
  2. You're using the URLSearchParams object. I think you ended up using this object to attempt to use JSONP? But JSONP is specifically designed to work with the "GET" verb not the "POST" verb. Also the server you're sending the JSONP request to has to support it.
  3. In your Headers area, you set the "Content-Type" to "application/x-www-form-urlencoded", this is strange because in your PHP code you actually decode the contents of the body as if it were a JSON string object. I think the reason this all might be kind of working is because "application/x-www-form-urlencoded" is basically a QueryString inside the body of your "POST" request. This is also likely allowing you to get around your CORS issue.
  4. You need to be consistent with your "Content-Type", right now you are sending a QueryString structure in your body to the PHP server, on the server you interpret the body as JSON, this is a mismatch.

I want to be clear though again, that my PHP experience is lacking. You say this is actually emailing you the parameters, so PHP could be doing some magic for you. I can't explain why it's returning NULL in the response yet it obviously was able to parse the data out and email it to you. You will probably want to seek out more information from some PHP folks.


UPDATE

Based on your feedback, it looks like your PHP code isn't returning json. I'm not a PHP expert, but it looks like you need to do this.

echo json_encode($value);//replaces: echo $value ->name;

If I understand what is going on, just including the header isn't enough for PHP to return your data json format.

Also remove the "console.log(res);" and the brackets. As rinukkusu points out in the comments, you have to be careful when using lambda bracket notation.


It sounds like the server you are posting to isn't returning its results in JSON. Depending on the server configuration specifically asking for json might give you the results you're looking for, for example in your code I would add another header to tell the server you would like the results in json. If that doesn't help I would also log the response to the console so you can see the results you're getting back.

let headers = new Headers();
headers.append('Content-Type','application/x-www-urlencoded');
//headers.append('Access-Control-Allow-Origin','*');
headers.append('Accept','application/json');//<-------
return this._http.post(this._mailUrl, body.toString(), { headers: headers })
    .map(res => {
         console.log(res);//<------------
         res.json();
     })
    .catch(this.handleError)

If the res object is empty you might want to watch the http traffic through the browser debugger or fiddler2 and see what is actually happening with the communications.

Since you have that cors header commented out, I just want to point out that if you accept json and you are doing a cross domain request then the server will need to respond back with specific headers in the reponse that the browser needs before it will allow the data to be usable.

Community
  • 1
  • 1
Dan Simon
  • 784
  • 5
  • 7
  • Careful though, with adding brackets to lambdas you have to return something, because it only implicitly returns without brackets -> `return res.json();` (Is not relevant to the question, just a friendly reminder) – rinukkusu Jul 18 '16 at 10:06
  • 1
    @user3094909 - updated my answer to provide further guidance based on your feedback. – Dan Simon Jul 18 '16 at 14:32
  • @DanSimon - thanks for your input. large changes in code, I updated. Hope all is much clearer now. – Fred30 Jul 21 '16 at 10:02
  • @user3094909 - Looking at your new code, I still think this is coming down to your php code as the issue(also you pasted your service code twice, your component code is also you service code right now). The only time you set the value on $formData is to turn it into object through deserialization. Please review my update on my answer and try that, then let me know the results. – Dan Simon Jul 21 '16 at 12:29
  • If I `echo json_encode($formData)` , the form parameters go through, but the server returns "null" – Fred30 Jul 21 '16 at 17:46
  • @user3094909 - When you say 'returns "null"', where are you seeing this? Are you using something like Fiddler2 to look at the http traffic or the dev tool for the browser? Can you also clarify what you mean by 'form parameters go through', do you mean you get an email with the parameters you expect? – Dan Simon Jul 21 '16 at 19:57
  • @DanSimon Thank you so much for your help again. I see this with the dev tool in FireFox. In the tab Network > Parameters, the form data appear. The Network > Answer a null (undefined). Yes, I get in an email with the form values. – Fred30 Jul 22 '16 at 13:09
  • @user3094909 - I have updated my answer, I'm not sure it will be that helpful though. You will probably need to get someone with PHP experience to help you. – Dan Simon Jul 25 '16 at 07:57