Utilizing a file type validator in SurveyJs: A guide

Is there a way to validate uploaded documents on a form using surveyJs and typescript with a custom validator before the file is uploaded? The current issue I am facing is that the validator gets called after the upload, resulting in an API error for unsupported file types. How can I ensure validation and display errors before the uploading process? Any help would be appreciated.

Below is the JSON snippet:

{
        "name": "document",
        "type": "file",
        "title": {
            "zh-cn": "6. 商业登记证",
            "zh-tw": "6. 商業登記證",
            "default": "6. Business registration certificate"
        },
        "maxSize": 10485760,
        "isRequired": true,
        "description": "{   \"type\": \"url\",   \"label\": {     \"default\": \"What does it look like?\",     \"zh-cn\": \"这个文件是什么?\",     \"zh-tw\": \"這個文件是什麼?\"   },   \"value\": \"/assets/images/sample_BR.jpg\" }",
        "acceptedTypes": ".pdf, .jpg, .png",
        "requiredErrorText": {
            "zh-cn": "请上传有效的公司商业登记证",
            "zh-tw": "請上傳有效的公司商業登記證",
            "default": "Please upload valid business registration certificate"
        },
        "allowImagesPreview": false,
        "descriptionLocation": "underInput",
        "validators": [{
            "type": "expression",
            "expression": "isJpgPngOrPdfFile({document}) == true",
            "text": "Invalid file format, please upload your document in png, jpeg or pdf format."
        }]
    }

Related TypeScript code:

Survey.FunctionFactory.Instance.register('isJpgPngOrPdfFile', this.isJpgPngOrPdfFile);

isJpgPngOrPdfFile(documents) {
  console.log(typeof documents + ':' + documents);
  if (documents.length < 1) return false;

  var fileValue = documents[0];
  var checkFile = function(file) {
    return (
      !file ||
      !file.name ||
      file.name.toLowerCase().endsWith('.png') ||
      file.name.toLowerCase().endsWith('.jpg') ||
      file.name.toLowerCase().endsWith('.pdf') ||
      file.name.toLowerCase().endsWith('.jpeg')
    );
  };
  if (Array.isArray(fileValue)) {
    return fileValue.every(checkFile);
  }
  return checkFile(fileValue);
}

Snippet from onUploadMethod function:

async onFileUpload(s, options) {
if (options.files && options.files.length) {
  const file = options.files[0];
  try {
    const data: any = await this.authService.uploadFile(file.name, file, file.type);
    options.callback(
      'success',
      options.files.map((item: File) => {
        return {
          file: item,
          content: data.code
        };
      })
    );
    const aTags = document.querySelectorAll(`[href='${data.code}']`);
    if (aTags.length) {
      (aTags[0] as HTMLAnchorElement).href = data.documentUrl;
      (aTags[0] as HTMLAnchorElement).innerHTML = data.name;
      (aTags[0] as HTMLAnchorElement).target = '_blank';
    }
  } catch (e) {
   
  }
}
}

Answer №1

I discovered the solution for validating file types and displaying a custom message when an unsupported file type is uploaded by using the addError() method.

async onFileUpload(s, options) {
if (options.files && options.files.length) {
  const file = options.files[0];
  try {
    const data: any = await this.authService.uploadFile(file.name, file, file.type);
    options.callback(
      'success',
      options.files.map((item: File) => {
        return {
          file: item,
          content: data.code
        };
      })
    );
    const aTags = document.querySelectorAll(`[href='${data.code}']`);
    if (aTags.length) {
      (aTags[0] as HTMLAnchorElement).href = data.documentUrl;
      (aTags[0] as HTMLAnchorElement).innerHTML = data.name;
      (aTags[0] as HTMLAnchorElement).target = '_blank';
    }
  } catch (e) {
    options.question.addError(new Survey.CustomError(e.error.message));
    options.callback('error');
    return;
  }
}

}

Check out this example in action : https://plnkr.co/edit/8DSqU2scJ32DXXGP

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Creating a HTTP Post request in Angular with DocRaptor to receive the download URL in the response

Struggling to integrate Angular5 with DocRaptor has led me to hit a roadblock. Surprisingly, the DocRaptor website lacks any documentation on how to combine it with Angular, only offering a beginner's guide for 'other'. I've scoured thr ...

Encountered a runtime error while processing 400 requests

Current Situation: When authenticating the username and password in my Ionic 2 project using WebApi 2 token authentication, a token is returned if the credentials are correct. However, a 400 bad request error is returned if the credentials are incorrect. ...

Subscribing to Observables in Angular Services: How Using them with ngOnChanges Can Trigger Excessive Callbacks

Consider the following scenario (simplified): Main Component List Component List Service Here is how they are connected: Main Component <my-list [month]="month"></my-list> List Component HTML <li *ngFor="let item in list | async>&l ...

The interface is incompatible with the constant material ui BoxProps['sx'] type

How can I make the interface work for type const material ui? I tried to register an interface for sx here, but it keeps giving me an error. import { BoxProps } from '@mui/material'; interface CustomProps { sx: BoxProps['sx&apo ...

Using Promise.all like Promise.allSettled

I am looking to streamline the handling of Promise.allSettled in a more generic way. Currently when using allSettled, it returns a list of both fulfilled and rejected results. I find this cumbersome and do not want to handle it everywhere in my code. My g ...

Resetting the datetime-local input to its initial value (ngModel) in template forms

In my Angular 6 template form, the user can modify the date/time in the datetime-local input after loading it with the latest data. However, I am struggling to reset the input back to the original date/time (loaded from array "one.classTimesLogOffRevised") ...

Angular - Managing unexpected routes for customized functionality

I am in the process of creating an app with Angular 6 and I'm faced with handling unknown routes within my application. For instance: Instagram has a default page (instagram.com), but if you type in (instagram.com/user) it redirects you to the user ...

How can I attach a click event listener to an Angular 2 ui-router <section ui-view> element?

In my Angular 2 application, I have a list called 'views' that contains paths to multiple images. Using ng-repeat, I cycle through these images and display them one by one in a ui-view element. I want to add an event listener so that when an imag ...

Standing alone, an argument can never be fully validated without

Recently, while delving into the valuable resource titled Effective TypeScript by Dan Vanderkam, I stumbled across an intriguing scenario that left me puzzled. Within a code snippet presented in the book, there was a line - shape; that seemed perplexing ...

Concealing Bootstrap Dialog in Angular 6 through Component隐藏Angular 6中

I have been struggling to hide a bootstrap dialog from a component with no success. Here is my Dialog code: <div class="modal fade" id="loading_video_upload" tabindex="-1" role="dialog" aria-labelledby="loading_video_upload_label" aria-hidde ...

How can you modify a button in Ionic 2 based on the login status, using a modal to redirect to a different page once authenticated?

I have a button on my main page that is supposed to display 'Log out' when the user is currently logged in, and 'Log in' when there is no active user session. Clicking on the login button opens a modal. After successful login, the user ...

Change the content of an ion-card in Ionic2 dynamically

After fetching a list of books from the backend API provider, I am presented with sample data that looks like this: { "success":true, "books":[ { "id":1000, "book_code":"CC219102", "read_status":"completed", ...

TimeStamp Recorder - Typescript

I'm trying to create a timer that counts the time when a button is pressed. Currently, I have managed to display the minutes and seconds on the screen as soon as the button is clicked. For example: 21(min):02(sec) What I am struggling with is updati ...

Can you explain the distinction between any[] and [] in TypeScript?

Here is an example that successfully works: protected createGroups(sortedItems: Array<TbpeItem>): any[] { let groups: any[] = []; return groups; } However, the second example encounters a TypeScript error: type any[] not assignable to ...

Checking email format in Angular

I am currently facing an issue where users are able to successfully submit a form even after entering an invalid email format. Despite receiving an error message, the form still gets submitted. It is important to note that I am not using formGroup. Below ...

Removing fields when extending an interface in TypeScript

Attempting to extend the ISampleB interface and exclude certain values, like in the code snippet below. Not sure if there is an error in this implementation export interface ISampleA extends Omit<ISampleB, 'fieldA' | 'fieldB' | &apos ...

"TypeScript function returning a boolean value upon completion of a resolved promise

When working on a promise that returns a boolean in TypeScript, I encountered an error message that says: A 'get' accessor must return a value. The code snippet causing the issue is as follows: get tokenValid(): boolean { // Check if curre ...

Embarking on a New Project with Cutting-Edge Technologies: Angular, Node.js/Express, Webpack, and Types

Recently, I've been following tutorials by Maximilian on Udemy for guidance. However, I have encountered a roadblock while trying to set up a new project from scratch involving a Node/Express and Angular 4 application. The issue seems to stem from the ...

Connecting Angular modules via npm link is a great way to share common

Creating a project with a shared module that contains generic elements and components, such as a header, is my goal. This shared module will eventually be added as a dependency in package.json and installed through Nexus. However, during the development ph ...

Angular's GET HTTP request has resulted in a 500 error message, specifically the Internal Server Error

Attempting to send a GET request to the server where only authenticated users can access a specific route ("/user") after logging in. However, even after a successful login, users are unable to gain access to the "/user" route. A middleware function named ...