Ionic camera only shows when i tap a form text field

I have an app the uses the camera to upload a base64 image as well as form data.
On iOS when i tap a button to take a picture the camera or gallery browser does not launch unless i tap into a text field.
In other words as the virtual keyboard shows up the camera popup takes over and shows and the keyboard disappears.

Your help will be appreciated.

Thanks

Hey @ZimNerd, can you provide the html and controller code please?

HTML

<ion-header>
    <ion-navbar>
        <button ion-button menuToggle>
            <ion-icon name="menu"></ion-icon>
        </button>
        <ion-title>
            Submit Claim

        </ion-title>
    </ion-navbar>
</ion-header>
<ion-content padding id="page7" class="bg-light-grey max95">
    <form id="submitClaim-form4" enctype="multipart/form-data" [formGroup]="submit_claim_form"
          (ngSubmit)="submitClaim(submit_claim_form.value)">
        <ion-list id="submitClaim-list3">
            <ion-item id="submitClaim-input15" class="spacer15 defy-input">
                <ion-datetime displayFormat="YYYY-MM-DD" min="2017-03-01" max="{{maxDate}}"
                              placeholder="Transaction Date" formControlName="transaction_date"
                              class="form-control" name="transaction_date"></ion-datetime>
            </ion-item>
            <div class="validation-errors">
                <ng-container *ngFor="let validation of validation_messages.transaction_date">
                    <div class="error-message"
                         *ngIf="submit_claim_form.get('transaction_date').hasError(validation.type) && (submit_claim_form.get('transaction_date').dirty || submit_claim_form.get('transaction_date').touched)">
                        {{ validation.message }}
                    </div>
                </ng-container>
            </div>
            <ion-item id="submitClaim-input16" class="spacer15 defy-input">
                <ion-input type="text" placeholder="Invoice Number"
                           formControlName="invoice_number"
                           class="form-control"
                           name="invoice_number"></ion-input>
            </ion-item>
            <div class="validation-errors">
                <ng-container *ngFor="let validation of validation_messages.invoice_number">
                    <div class="error-message"
                         *ngIf="submit_claim_form.get('invoice_number').hasError(validation.type) && (submit_claim_form.get('invoice_number').dirty || submit_claim_form.get('invoice_number').touched)">
                        {{ validation.message }}
                    </div>
                </ng-container>
            </div>
            <ion-item id="submitClaim-select4" class="spacer15 defy-input">
                <ion-select placeholder="Choose Store" formControlName="store_id"
                            class="form-control" name="store">
                    <ion-option *ngFor="let store of myStores" [value]="store.storeid">
                        {{store.store_name}}
                    </ion-option>


                </ion-select>
            </ion-item>
            <div class="validation-errors">
                <ng-container *ngFor="let validation of validation_messages.store_id">
                    <div class="error-message"
                         *ngIf="submit_claim_form.get('store_id').hasError(validation.type) && (submit_claim_form.get('store_id').dirty || submit_claim_form.get('store_id').touched)">
                        {{ validation.message }}
                    </div>
                </ng-container>
            </div>
        </ion-list>
        <img [src]="sanitizer.bypassSecurityTrustResourceUrl(fullbase64Image)" *ngIf="base64Image" style="width: 100%"/>
        <h6 [hidden]="base64Image !== null">Please Select file!</h6>

        <ion-toolbar color="primary" class="spacer15 defy-input">
            <ion-buttons>
                <button ion-button type="button" icon-left (click)="presentActionSheet()">
                    <ion-icon name="camera"></ion-icon>
                    Upload Proof Of Sale
                </button>
            </ion-buttons>
        </ion-toolbar>
        <ion-input type="hidden" [value]="base64Image"
                   formControlName="file_data"
                   class="form-control"></ion-input>
        <div class="validation-errors">
            <ng-container *ngFor="let validation of validation_messages.file_data">
                <div class="error-message"
                     *ngIf="submit_claim_form.get('file_data').hasError(validation.type) && (submit_claim_form.get('file_data').dirty || submit_claim_form.get('file_data').touched)">
                    {{ validation.message }}
                </div>
            </ng-container>
        </div>
        <ion-item id="submitClaim-textarea1" class="spacer5 defy-input">
            <ion-textarea formControlName="additional_information"
                          class="form-control" placeholder="Additional information"></ion-textarea>
        </ion-item>
        <ion-item id="submitClaim-select7" class="spacer15 defy-input" *ngIf="myGroupedProducts">
            <ion-select placeholder="Product Type" formControlName="productTypes" name="productTypes"
                        class="form-control" (ionChange)="valueChange(submit_claim_form.get('productTypes').value)"
                        name="productTypes">
                <ion-option *ngFor="let producttype of myGroupedProducts" [value]="producttype.title">
                    {{ producttype.title }}
                </ion-option>
            </ion-select>
        </ion-item>
        <ion-item id="submitClaim-select8" *ngIf="productType" class="spacer15 defy-input">
            <ion-select *ngIf="submit_claim_form.get('productTypes').value"
                        placeholder="Product Category"
                        formControlName="productCats" name="productCats"
                        class="form-control" (ionChange)="onChangecat(submit_claim_form.get('productCats').value)">
                <ion-option *ngFor="let productsubcategory of myGroupedProducts | ProductPipe:productType"
                            [value]="productsubcategory.product_name+'--'+productsubcategory.product_code ">
                    {{ productsubcategory.product_name}} ({{productsubcategory.product_code}})
                </ion-option>
            </ion-select>
        </ion-item>

        <ion-grid *ngIf="submit_claim_form.get('productCats').value">
            <ion-row>
                <ion-col col-8>
                    <ion-item id="submitClaim-select10" class="defy-input">
                        <ion-input type="number" *ngIf="submit_claim_form.get('productCats').value"
                                   placeholder="Quantity" formControlName="productModelsCount"
                                   class="form-control">
                        </ion-input>
                    </ion-item>
                </ion-col>
                <ion-col col-4>
                    <button id="addproduct" type="button" ion-button color="assertive"
                            (click)="addProduct(submit_claim_form.get('productTypes').value,submit_claim_form.get('productCats').value,submit_claim_form.get('productModelsCount').value)"
                            class="right">Add
                    </button>
                </ion-col>
            </ion-row>
        </ion-grid>
        <ion-grid *ngIf="claimProducts">
                <ion-row>
                    <ion-col col-2>
                        Code
                    </ion-col>
                    <ion-col col-7>
                        Model
                    </ion-col>

                    <ion-col col-3>
                        Count
                    </ion-col>
                </ion-row>
        </ion-grid>
        <ion-grid *ngIf="claimProducts">
            <ion-row *ngFor="let claimdata of claimproduct.data; let i = index" class="product-list stripped">
                <ion-row *ngIf="claimdata.type">
                    <ion-col col-2>
                        {{ claimdata.code }}
                    </ion-col>
                    <ion-col col-7>
                        {{ claimdata.model }}
                    </ion-col>
                    <ion-input type="hidden"
                               [value]="claimdata.code" formControlName="code"
                               class="form-control"></ion-input>
                    <ion-col col-2>
                        <ion-input id="claim--{{claimdata.code}}--{{claimdata.quantity}}" type="text"
                                   [value]="claimdata.quantity"
                                   formControlName="quantity"
                                   class="form-control"></ion-input>
                    </ion-col>
                    <ion-col col-1>
                        <ion-icon name="remove-circle" (click)="removeRow(i)" class="deletebtn"></ion-icon>
                    </ion-col>
                </ion-row>
            </ion-row>
        </ion-grid>
        <div class="validation-errors">
            <ng-container *ngFor="let validation of validation_messages.code">
                <div class="error-message"
                     *ngIf="submit_claim_form.get('code').hasError(validation.type) && (submit_claim_form.get('code').dirty || submit_claim_form.get('code').touched)">
                    {{ validation.message }}
                </div>
            </ng-container>
        </div>

        <div class="spacer15"></div>
        <button id="submitClaim-button5" ion-button color="assertive" class="right text-right" type="submit" text-right
                right [disabled]="!submit_claim_form.valid">
            Submit
        </button>
    </form>
    <div class="spacer20"></div>

</ion-content>


Controller

import {Component} from '@angular/core';
import {
    App,
    NavController,
    ActionSheetController,
    ToastController,
    Platform,
    LoadingController,
    Loading,
    AlertController
} from 'ionic-angular';
import {Camera} from '@ionic-native/camera';
import {TabsPage} from '../tabs/tabs';
import {RestapiService} from "../../providers/restapi-service/restapi-service";
import {HomePage} from "../home/home";
import 'rxjs/add/operator/map';
import 'rxjs/Rx';
import {DomSanitizer} from "@angular/platform-browser";
import {LoginPage} from "../login/login";
import {FormBuilder, FormControl, FormGroup, Validators} from "@angular/forms";


declare let cordova: any;

@Component({
    selector: 'page-submit-claim',
    templateUrl: 'submit-claim.html',
})

export class SubmitClaimPage {
    rootPage: any = HomePage;
    pages: any;
    products: any;
    productTypes = "";
    productModelsCount = "";
    productCats = "";
    userData = sessionStorage.getItem('userData');
    loading: Loading;
    base64Image: string = null;
    fullbase64Image: string = null;
    claimData: any;
    myStores: any;
    claimProducts: any;
    Image: any;
    groupedProducts: any;
    mySession: any;
    claimproduct = {data: [{}]};
    productCat: any;
    grouped: any;
    maxDate: any;
    myGroupedProducts: any;
    stores: {};


    claim = {
        transaction_date: "",
        invoice_number: "",
        store_id: "",
        storemember_id: sessionStorage.getItem('userData.storemember_id'),
        additional_information: "",
        file_data: "",
        product_claim_items: [
            {
                product_code: ""
            }
        ]
    };

    productType: any = "";
    i: any = '';
    submit_claim_form: FormGroup;


    constructor(public app: App, public sanitizer: DomSanitizer, public formBuilder: FormBuilder, public navCtrl: NavController, public restapiService: RestapiService, private alertCtrl: AlertController, private camera: Camera, public actionSheetCtrl: ActionSheetController, public toastCtrl: ToastController, public platform: Platform, private loadingCtrl: LoadingController) {
        this.grouped = sessionStorage.getItem('groupedproducts');
        this.getStores();
        this.ionViewCanEnter();
        this.getGroupedProducts();
        if (this.claimproduct.data.length < 1) {
            this.claimproduct.data.splice(0, 1);
        }
        this.maxDate = new Date().toISOString().slice(0, 10);

    }

    ionViewCanEnter() {

        this.submit_claim_form = this.formBuilder.group({
            transaction_date: new FormControl('', Validators.required),
            invoice_number: new FormControl('', Validators.required),
            store_id: new FormControl('', Validators.required),
            file_data: new FormControl('', Validators.required),
            productModelsCount: new FormControl(''),
            productCats: new FormControl(''),
            productTypes: new FormControl(''),
            quantity: new FormControl('', Validators.required),
            code: new FormControl('', Validators.required),
            additional_information: new FormControl('')
        });

        return this.restapiService.validateSession()
            .then((session) => {
                    this.mySession = session;
                    if (this.mySession['status'] != 'ok') {
                    }

                },
                (err) => {
                    let body = JSON.parse(err._body);
                    this.goToLogin(body.error_message);
                });

    }


    validation_messages = {
        'transaction_date': [
            {type: 'required', message: 'Transaction date cannot be empty.'}
        ],
        'invoice_number': [
            {type: 'required', message: 'Invoice cannot be empty.'}
        ],
        'store_id': [
            {type: 'required', message: 'Store cannot be empty.'}
        ],
        'product_code': [
            {type: 'required', message: 'Please add atleast one product.'}
        ],
        'file_data': [
            {type: 'required', message: 'Please attach proof of payment.'}
        ],
        'code': [
            {type: 'required', message: 'Add atleast one product.'}
        ]
    };


    valueChange(selectedValue: any) {
        this.productType = selectedValue;
    }

    onChangecat(selectedcatValue: any) {
        this.productCat = selectedcatValue;
    }


    addProduct(type: any, model: any, count: any) {
        let res = model.split("--");
        let code = res[1];
        let models = res[0];


        this.claimproduct.data.push({type: type, model: models, code: code, quantity: count});
        this.claim.product_claim_items = [];
        this.showObject(this.claimproduct.data);
        this.claimProducts = this.claimproduct.data.length;
        this.submit_claim_form.patchValue({
            productTypes: '',
        });
        this.submit_claim_form.patchValue({
            productCats: '',
        });
        this.submit_claim_form.patchValue({
            productModelsCount: '',
        });

    }

    removeRow(arrIndex) {
        this.claimproduct.data.splice(arrIndex, 1);
        this.showObject(this.claimproduct.data);
    };

    showObject(obj) {
        this.claim.product_claim_items=[];
        let result = "";
        for (let p of obj) {
            if (p.hasOwnProperty('code') && p.hasOwnProperty('quantity')) {
                for (let i = 0; i < p['quantity']; i++) {
                    this.claim.product_claim_items.push({product_code: p['code']})
                }
            }
        }

        return result;
    }

    getGroupedProducts() {
        this.restapiService.getGroupedProducts()
            .then((groupedproducts) => {
                    this.groupedProducts = groupedproducts['data'];
                    this.myGroupedProducts = [];
                    for (let main in this.groupedProducts) {
                        this.myGroupedProducts.push(this.groupedProducts[main])
                    }
                    sessionStorage.setItem('groupedproducts', this.myGroupedProducts);

                },
                (err) => {
                    let body = JSON.parse(err._body);
                    this.showError(err.statusText, body.error_message);
                });
    }

    getStores() {
        this.showLoading('Loading stores...');
        this.restapiService.getStores()
            .then((stores) => {
                    this.myStores = stores['data'];
                    sessionStorage.setItem('stores', this.myStores);
                    this.loading.dismiss();
                },
                (err) => {
                    let body = JSON.parse(err._body);
                    this.showError(err.statusText, body.error_message);
                })
    }


    submitClaim(requestData) {
        console.log(requestData);

        this.claim.transaction_date = requestData.transaction_date;
        this.claim.invoice_number = requestData.invoice_number;
        this.claim.store_id = requestData.store_id;
        this.claim.additional_information = requestData.additional_information;
        this.claim.file_data = requestData.file_data;
        console.log(this.claim);

        this.showLoading('Submitting claim...');
        this.restapiService.submitClaim(this.claim)
            .then((result) => {
                this.loading.dismiss();
                this.claimData = result;
                let results = JSON.parse(this.claimData._body);
                this.goToTabs(results);
                this.presentToast('Claim submitted successfully');
            }, (err) => {
                let body = JSON.parse(err._body);
                this.showError(err.statusText, body.error_message);
            });
    }

    showError(title, textbody) {
        this.loading.dismiss();

        let alert = this.alertCtrl.create({
            title: title,
            subTitle: '',
            message: textbody,
            buttons: ['OK']
        });
        alert.present(prompt);
    }

    public takePicture(sourceType) {
        // Create options for the Camera Dialog
        console.log("Camera action");
        let options = {
            sourceType: sourceType,
            destinationType: this.camera.DestinationType.DATA_URL,
            targetWidth: 840,
            targetHeight: 1200,
            correctOrientation: true
        };

        // Get the data of an image
        this.camera.getPicture(options).then((imageData) => {
            this.base64Image = imageData;
            //this.base64Image = "data:image/jpeg;base64," + imageData;
            let imageType = this.guessImageMime(imageData);
            this.fullbase64Image = "data:" + imageType + ";base64," + imageData;
        }, (err) => {
            this.presentToast('Error while selecting image.');
            return false;
        });
    }

    public presentActionSheet() {
        let actionSheet = this.actionSheetCtrl.create({
            title: 'Select Image Source',
            buttons: [
                {
                    text: 'Load from Library',
                    icon: 'images',
                    handler: () => {
                        this.takePicture(this.camera.PictureSourceType.PHOTOLIBRARY);
                    }
                },
                {
                    text: 'Use Camera',
                    icon: 'camera',
                    handler: () => {
                        this.takePicture(this.camera.PictureSourceType.CAMERA);
                    }
                },
                {
                    text: 'Cancel',
                    role: 'cancel'
                }
            ]
        });
        actionSheet.present();
    }


    guessImageMime(data) {
        if (data.charAt(0) == '/') {
            return "image/jpeg";
        } else if (data.charAt(0) == 'R') {
            return "image/gif";
        } else if (data.charAt(0) == 'i') {
            return "image/png";
        } else if (data.charAt(0) == 'J') {
            return "application/png";
        }
    }


    showLoading(data) {
        this.loading = this.loadingCtrl.create({
            content: data,
            dismissOnPageChange: false,
            spinner: 'dots'
        });
        this.loading.present();
    }


    private presentToast(text) {
        let toast = this.toastCtrl.create({
            message: text,
            duration: 3000,
            position: 'middle',
            cssClass: 'defyToast'
        });
        toast.present();
    }

    goToTabs(params) {
        if (!params) params = {};
        this.navCtrl.setRoot(TabsPage, params);
    }

    goToSubmitClaims(params) {
        if (!params) params = {};

        this.navCtrl.setRoot(TabsPage, params);
        this.navCtrl.push(SubmitClaimPage);
    }

    goToLogin(params) {
        if (!params) params = {};
        this.navCtrl.setRoot(LoginPage);
    }

}

@quieterkali please find the code above.

<ion-input type=“hidden” [value]="base64Image"
formControlName="file_data"
class=“form-control”>

So this is where your image is coming in right?
Personally when using the TakePicture() function I haven’t needed the form values, I just use a button then pass the saved base64image string to the method that is saving it.

@matt4759 please refer to the attached image. That is how my form look like.
The image must also show on the form that’s why i included the upload button onto the form.

Well so the problem is that your keyboard comes up? I think the reason the keyboard is coming up is because its an ion-input element, I dont believe the issue lies anywhere within your takepicture method or presentActionSheet method.

But! I did some googling around and also found this : Prevent keyboard popup
"Just solved this by adding ng-readonly=“true” to the input field."
May be worth a shot?

The camera does not show when i click the upload button to capture image. It will only show when i click on a different input. The moment i tap in a text field that when the camera shows up.

I have a similar problem when tapping the button to open the camera, it doesn’t show up until I tap on the status bar. found a solution?

I haven’t found the solution as yet. ANyone facing similar issue?

Is that happening on IOS6? cause is working fine on Android but not on IOS

iOS 10.3 and emulator.

Dang, I am stuck. I can’t publish my app because of the issue. Also noticed is doing the same behavior with other plugins such Barcode and Imagepicker. As soon I tap on the status bar (top) or pull down the native ios notification screen it fire the plugin (barcode, image picker or camera)