PDFViewer & Nextjs - importFormFields, exportFormFields, dataSync

Hi

  1. I want to synchronize form fields and pdfViewer, but cannot make it with success.
  2. I want to make importFormFields to pdfViewer, but cannot make it with success.
  3. I want to make exportFormFields to pdfViewer, but cannot make it with success


My code is a below
How can I solve the problems with PDFViewer component?
Best regards,

"use client";
import { useEffect, useState } from 'react';
import { PdfViewerComponent, Toolbar, Magnification, Navigation, Annotation, LinkAnnotation, BookmarkView, ThumbnailView, Print, TextSelection, TextSearch, FormFields, FormDesigner, PageOrganizer, Inject } from '@syncfusion/ej2-react-pdfviewer';
import '@syncfusion/ej2-react-pdfviewer/styles/material.css';
import { L10n } from '@syncfusion/ej2-base';

const Page = () => {
  const [pdfUrl, setPdfUrl] = useState(null);
  const [loading, setLoading] = useState(true);

  // FormData
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    gender: 'Male',
    dob: '',
    state: 'Alabama',
    newsletter: false
  });
  const handleChange = (e) => {
    const { name, value, type, checked } = e.target;

    // Handle checkboxes separately
    if (type === 'checkbox') {
      setFormData({
        ...formData,
        [name]: checked,
      });
    } else {
      setFormData({
        ...formData,
        [name]: value,
      });
    }

    // TODO : each data changed PDF Form update automatically
  };
  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('Form submitted:', formData);
    alert('Form submitted successfully!');
  };
  // Turkish Language Setting
  L10n.load({
    'tr-TR': {
      'PdfViewer': {
        'PdfViewer': 'PDF Görüntüleyici',
        'Cancel': 'İptal',
        'Download file': 'Dosyayı indir',
        // Turkish language translations...
      }
    }
  });


  // PDF from local 'public' folder
  useEffect(() => {
    const fetchPdfBlob = async () => {
      const url = '/FormFillingDocument.pdf';
      fetchAndConvertToBase64(url)
        .then(base64String => {
          if (base64String) {
            setPdfUrl("data:application/pdf;base64," + base64String);
            setLoading(false);
          } else {
            console.error('Failed to convert PDF to Base64.');
            setLoading(false);
          }
        })
        .catch(error => {
          console.error('Error:', error);
          setLoading(false);
        });
    };

    fetchPdfBlob();
  }, []);
  // Fetch and Convert PDF to Base64
  function fetchAndConvertToBase64(url) {
    return new Promise((resolve, reject) => {
      fetch(url)
        .then(response => {
          if (!response.ok) {
            throw new Error('HTTP error! Status: ' + response.status);
          }
          return response.blob();
        })
        .then(blob => {
          blobToBase64(blob).then(resolve).catch(reject);
        })
        .catch(error => {
          console.error('Error fetching file:', error);
          reject(null);
        });
    });
  }
  // Convert Blob to Base64
  function blobToBase64(blob) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = function () {
        const base64String = reader.result ? reader.result.toString().split(',')[1] : '';
        resolve(base64String);
      };
      reader.onerror = function (error) {
        reject(error);
      };
      reader.readAsDataURL(blob);
    });
  }
  //PDF Loaded
  function documentLoaded(){
    console.log("pdf_loaded", new Date());
  }

  //FormField click
  function formFieldClicked(args) {
    const data = {
      id : args.field.id,
      name: args.field.name,
      value: args.field.value,
    };
    console.log('Form field data: ', data);
  }

  // SubmitForm Click (toolbar)
  // TODO : Problem on there : too slow response, waiting 5-10 seconds
  // I added loadingIndicator for see problem
  // delay comes from exportFormFieldsAsObject => Promise {<pending>}
  const toolbarClick = async (args) => {
    const viewer = document.getElementById('pdfviewer').ej2_instances[0];
 
    if (args.item && args.item.id === 'submitFormButton') {
      console.log('Form submission started...');
     
      const loadingIndicator = document.getElementById('loadingIndicator');
      if (loadingIndicator) {
        loadingIndicator.style.display = 'block';
      }
      try {
        const result = viewer.exportFormFieldsAsObject();
        console.log('Result from exportFormFieldsAsObject:', result);
       
        if (result && result.then) {
          const formSubmitData = await result;
          console.log('Form submission completed:', formSubmitData);
         
          downloadJSON(formSubmitData, 'form-submission.json');
          alert('Form submitted as JSON!');
        } else {
          console.error('exportFormFieldsAsObject did not return a Promise');
        }
      } catch (error) {
        console.error('Error submitting form:', error);
      } finally {
        // Hide the loading indicator when done
        if (loadingIndicator) {
          loadingIndicator.style.display = 'none';
        }
      }
    }
  };

 
  // Helper function to download JSON file
  function downloadJSON(data, filename) {
    const blob = new Blob([data], { type: 'application/json' });
    const link = document.createElement('a');
    link.rel='nofollow' href = URL.createObjectURL(blob);
    link.download = filename;
    link.click();
  }

  //Import Data from Json
  //TODO : Problem on there : importFormFields is not working
  function importFormField() {
    const viewer = document.getElementById('pdfviewer').ej2_instances[0];
    const setData = {
      name: 'Hamdi',
      email: 'hamdi@gmail.com',
      gender: 'Male',
      dob: '01.01.2000',
      state: 'Alabama',
      newsletter: false
    };
    setFormData(setData);
    let loadData = JSON.stringify(setData);
    viewer.importFormFields(loadData);
    console.log("Import Data", loadData);
  }
   
  //Export Data to Json
  //TODO : Problem on there : too slow response, waiting 5-10 seconds
  function exportFormField() {
    const viewer = document.getElementById('pdfviewer').ej2_instances[0];
    viewer.exportFormFieldsAsObject().then(function (value) {
      const exportdata = value;
      console.log("Export Data", exportdata);
    });
  }



  return (
    <div style={{margin: "0", padding: "0", height: "100%", overflow:"hidden"}}>
      {loading ? (
        <p>Loading...</p>
      ) : (
        <div>
          <button onClick={importFormField}>Import Form Data</button>
          <button onClick={exportFormField}>Export Data</button>

          <PdfViewerComponent
            id="pdfviewer"
            documentPath={pdfUrl}
            serviceUrl="https://services.syncfusion.com/react/production/api/pdfviewer"
            style={{ width: '100vw', height: '50vh' }}
            locale="tr-TR"
            enableLocalStorage = "true"
            documentLoad={documentLoaded}
            formFieldClick={formFieldClicked}
            toolbarSettings={{
              showTooltip: true,
              toolbarItems: [
                'PageNavigationTool', 'MagnificationTool',  
                { text: 'SubmitFormButton', tooltipText: 'Submit Form as JSON', id: 'submitFormButton' }
              ]
            }}
            toolbarClick={toolbarClick}
          >
            <Inject services={[ Toolbar, Magnification, Navigation, Annotation, LinkAnnotation, BookmarkView,
                               ThumbnailView, Print, TextSelection, TextSearch, FormFields, FormDesigner, PageOrganizer ]}/>
          </PdfViewerComponent>
        </div>
      )}
    <div style={{margin:"20px"}}>
      <h1>Form Data</h1>
      <form onSubmit={handleSubmit}>
        {/* Name Field */}
        <div style={{padding:"10px"}}>
          <label htmlFor="name">Name:</label>
          <input
            type="text"
            id="name"
            name="name"
            value={formData.name}
            onChange={handleChange}
            required
          />
        </div>

        {/* Email Field */}
        <div style={{padding:"10px"}}>          
          <label htmlFor="email">Email:</label>
          <input
            type="email"
            id="email"
            name="email"
            value={formData.email}
            onChange={handleChange}
            required
          />
        </div>

        {/* Gender Field */}
        <div style={{padding:"10px"}}>
          <label>Gender:</label>
          <label>
            <input
              type="radio"
              name="gender"
              value="Male"
              checked={formData.gender === 'Male'}
              onChange={handleChange}
            /> Male
          </label>
          <label>
            <input
              type="radio"
              name="gender"
              value="Female"
              checked={formData.gender === 'Female'}
              onChange={handleChange}
            /> Female
          </label>
          <label>
            <input
              type="radio"
              name="gender"
              value="Unspecified"
              checked={formData.gender === 'Unspecified'}
              onChange={handleChange}
            /> Unspecified
          </label>
        </div>

        {/* DOB Field */}
        <div style={{padding:"10px"}}>
          <label htmlFor="dob">Date of Birth:</label>
          <input
            type="text"
            id="dob"
            name="dob"
            value={formData.dob}
            onChange={handleChange}
            required
          />
        </div>

        {/* State Field */}
        <div style={{padding:"10px"}}>
          <label htmlFor="state">State:</label>
          <select
            id="state"
            name="state"
            value={formData.state}
            onChange={handleChange}
            required
          >
            <option value="Alabama">Alabama</option>
            <option value="California">California</option>
          </select>
        </div>

        {/* Newsletter Field */}
        <div style={{padding:"10px"}}>
          <label> Would you like to receive our
          Newsletter?
            <input
              type="checkbox"
              name="newsletter"
              checked={formData.newsletter}
              onChange={handleChange}
            />
          </label>
        </div>

        {/* Submit Button */}
        <div style={{padding:"10px"}}>
          <button type="submit">Submit</button>
        </div>
      </form>

      <pre>{JSON.stringify(formData, null, 2)}</pre>
    </div>
    </div>
  );
};

export default Page;




5 Replies

SK Sathiyaseelan Kannigaraj Syncfusion Team January 25, 2025 12:08 PM UTC

Hi Hamdi Boyaci,

Thank you for reaching out to us. We were able to reproduce the issue you mentioned regarding the failure to import the JSON file. We will validate this and provide further updates by January 28, 2025. However, the export functionality for JSON files was working as expected. Below, we have included the sample we tested. Kindly review it and confirm if you encountered any issues. If you are still facing problems, please provide a demo video and a sample to help us replicate the issue and offer an appropriate solution.

Sample we have tested
 


Regards,
Sathiyaseelan K



HB Hamdi Boyaci January 27, 2025 08:17 AM UTC

Thank for fixing import function.


How can I open password protected pdf file with programatically (not open password request popup) ?
This is not working, can you give correct solution for us ?
Best regards,

"use client";
import { useEffect, useState } from 'react';
import { PdfViewerComponent, Toolbar, Magnification, Navigation, Annotation, LinkAnnotation, BookmarkView, ThumbnailView, Print, TextSelection, TextSearch, FormFields, FormDesigner, PageOrganizer, Inject } from '@syncfusion/ej2-react-pdfviewer';
import '@syncfusion/ej2-react-pdfviewer/styles/material.css';

const Page = () => {
  const [pdfUrl, setPdfUrl] = useState(null);
  const [loading, setLoading] = useState(true);


  const onLoad = (args) => {
    const password = '123456789';
    args.viewer.load(pdfUrl, password);
  };

  //PDF Loaded
  function documentLoaded() {
    console.log("PDF loaded:", new Date());
    setLoading(false);
  }

  useEffect(() => {
    setPdfUrl('/FormFillingWithPwd.pdf');
  }, []);

  return (
    <div style={{ margin: "0", padding: "0", height: "100%", overflow: "hidden" }}>
      {loading ? (
        <p>Loading...</p>
      ) : (
        <div>
          <PdfViewerComponent
            id="pdfviewer"
            documentPath={pdfUrl}
            serviceUrl="https://services.syncfusion.com/react/production/api/pdfviewer"
            //resourceUrl="https://cdn.syncfusion.com/ej2/24.1.41/dist/ej2-pdfviewer-lib"
            style={{ width: '100vw', height: '50vh' }}
            load={onLoad}
            documentLoaded={documentLoaded}
          >
            <Inject services={[Toolbar, Magnification, Navigation, Annotation, LinkAnnotation, BookmarkView,
                               ThumbnailView, Print, TextSelection, TextSearch, FormFields, FormDesigner, PageOrganizer]} />
          </PdfViewerComponent>
        </div>
      )}
    </div>
  );
};

export default Page;



US Umamageshwari Shanmugam Syncfusion Team January 28, 2025 12:45 PM UTC

Hi Hamdi Boyaci,


You need to make the following changes to the controller file to import the form fields data into the server-side PDF viewer. Here is the code snippet for this.


Code snippet:

  

    public IActionResult ImportFormFields([FromBody] Dictionary<string, string> jsonObject)

    {

        PdfRenderer pdfviewer = new PdfRenderer(_cache);

        var importFormFieldData = GetDocumentPath(jsonObject["data"]);

        if (importFormFieldData == string.Empty)

        {

            var importformFieldDataObject = JsonConvert.DeserializeObject(jsonObject["data"]);

            if (importformFieldDataObject != null)

            {

                jsonObject["data"] = importformFieldDataObject.ToString();

            }

        }

        else

        {

            jsonObject["data"] = importFormFieldData;

        }

        object jsonResult = pdfviewer.ImportFormFields(jsonObject);

        return Content(JsonConvert.SerializeObject(jsonResult));

    }


You need to make following changes on the client side to load a password-protected document using created event without displaying the popup. Here is the code snippet for this.
 

 Code Snippet:

<PdfViewerComponent

          id="container"

          ref={(scope) => {

            viewer = scope;

          }}

          created={created}

          serviceUrl="https://localhost:44309/pdfviewer"

          style={{ height: '640px' }}

        >

</PdfViewerComponent>
 

function created() {

    let documentPath = 'form-filling-document.pdf';

    let password = 'Sync@123';

    viewer.load(documentPath, password);

  }


Please refer the following sample and let us know if you need any further assistance.

React Sample- ClientSample

Web Service Sample - ServiceSample

Regards,

Umamageshwari Shanmugam



HB Hamdi Boyaci January 28, 2025 01:28 PM UTC


For loading a password-protected document using created event without displaying the popup.

created={created}  is not solved the problem


1.png

code is :

"use client";
import { useEffect, useState } from 'react';
import { PdfViewerComponent, Toolbar, Magnification, Navigation, Annotation, LinkAnnotation, BookmarkView, ThumbnailView, Print, TextSelection, TextSearch, FormFields, FormDesigner, PageOrganizer, Inject } from '@syncfusion/ej2-react-pdfviewer';
import '@syncfusion/ej2-react-pdfviewer/styles/material.css';

const Page = () => {
  let viewer;

  function created() {
    console.log("created_start");
    let documentPath = "/FormFillingWithPwd.pdf";
    let password = '123456789';
    viewer.load(documentPath, password);
    console.log("created_end");

  }

  return (
    <div style={{ margin: "0", padding: "0", height: "100%", overflow: "hidden" }}>

        <div>
        <PdfViewerComponent
          id="container"
          ref={(scope) => {
            viewer = scope;
          }}
          created={created}
          serviceUrl="https://services.syncfusion.com/react/production/api/pdfviewer"
          resourceUrl="https://cdn.syncfusion.com/ej2/24.1.41/dist/ej2-pdfviewer-lib"
          style={{ height: '640px' }}
        >
            <Inject services={[Toolbar, Magnification, Navigation, Annotation, LinkAnnotation, BookmarkView,
                               ThumbnailView, Print, TextSelection, TextSearch, FormFields, FormDesigner, PageOrganizer]} />
          </PdfViewerComponent>
        </div>

    </div>
  );
};

export default Page;



SK Sathiyaseelan Kannigaraj Syncfusion Team January 29, 2025 02:18 PM UTC

Hi Hamdi Boyaci,

Thank you for the update. We have tested the same scenario of loading a password-protected PDF in the created event, but we did not encounter the issue. Below, we have provided a demo of our testing process. Kindly check whether you experience the issue in the sample we have provided. Additionally, please use only the serviceUrl and avoid the resourceUrl. If you are still facing any issues, kindly share a sample and the PDF file to help us replicate the problem and provide a solution.


Demo on loading pdf 


Regards,
Sathiyaseelan K


Loader.
Up arrow icon