FormData에 배열을 추가하고 AJAX를 통해 전송


109

ajax를 사용하여 배열, 텍스트 필드 및 파일이있는 다중 부분 양식을 제출하고 있습니다.

각 VAR을 기본 데이터에 추가합니다.

var attachments = document.getElementById('files'); 
var data= new FormData();

for (i=0; i< attachments.files.length; i++){
    data.append('file', attachments.files[i]);
    console.log(attachments.files[i]);

    data.append ('headline', headline);
    data.append ('article', article);
    data.append ('arr', arr);
    data.append ('tag', tag);

그런 다음 ajax 함수를 사용하여 PHP 파일로 보내 SQL DB에 저장합니다.

$.ajax({    
    type: "post",
    url: 'php/submittionform.php',
    cache: false,
    processData: false,
    contentType: false,
    data: data,
    success: function(request) {$('#box').html(request); }
})

그러나 PHP 측에서는 arr배열 인 변수가 문자열로 나타납니다.

Form 데이터로 ajax를 사용하지 않고 간단한 $.POST옵션을 사용 하면 PHP 측에서 배열로 가져 오지만 파일도 보낼 수 없습니다.

어떤 해결책?

답변:


93

몇 가지 옵션이 있습니다.

JSON 문자열로 변환 한 다음 PHP에서 구문 분석 (권장)

JS

var json_arr = JSON.stringify(arr);

PHP

$arr = json_decode($_POST['arr']);

또는 @Curios의 방법을 사용하십시오.

비아 어레이를 전송 FormData.


권장하지 않음 : 데이터를 직렬화 한 다음 PHP에서 역 직렬화

JS

// Use <#> or any other delimiter you want
var serial_arr = arr.join("<#>"); 

PHP

$arr = explode("<#>", $_POST['arr']);

1
문제는 배열에 공백과 문장 부호가있는 REAL 텍스트 줄이 포함되어 있다는 것입니다. 나는 그것을 엉망으로 만들고 싶지 않다.
shultz

3
JSON으로 인코딩하고 구문 분석 할 때 데이터가 손실되지 않습니다. 한번 시도해)
리처드 드 위트에게

자동 매핑 또는 이와 유사한 것과 함께 asp.net을 사용하는 경우 @Curious 대답이 필요합니다.
Martín Coll

1
@Richard de Wit File 또는 FormData와 같은 데이터가있는 경우 json.stringfy에서 해당 데이터를 잃게됩니다
Mohsen

나는 더 나은, 더 단순한 문자열을 좋아합니다. []를 사용하여 배열 배열을 전달하려면 일종의 재귀를 수행해야하지만 그렇게 할 수 있다는 것을 아는 것이 좋습니다.
Chopnut

260

FormData다음과 같은 방법으로 배열을 보낼 수도 있습니다 .

var formData = new FormData;
var arr = ['this', 'is', 'an', 'array'];
for (var i = 0; i < arr.length; i++) {
    formData.append('arr[]', arr[i]);
}

따라서 arr[]간단한 HTML 양식을 사용하는 것과 동일한 방식으로 작성할 수 있습니다 . PHP의 경우 작동합니다.

이 기사가 유용 할 것입니다. 쿼리 문자열 내에서 배열을 전달하는 방법?


1
@Oleg 작성할 필요가 무엇 arr[]에가 formData.append('arr[]', arr[i]);? 왜 arr정확 하지 않습니까? 나는 둘 다 시도했지만 arr[]작동했습니다.
Totoro

@Totoro 왜냐하면 arr각 루프 반복에서이 값을 재정의하고 결국 최종 값은 마지막 배열 요소와 같지만 전체 배열이 아니기 때문입니다
Oleg

@Oleg 재정의하는 경우에서 무엇이 다른지 arr[], 왜 arr[]재정의 되지 않습니까? arr[]또한 문자열입니다. 그리고 둘 다 테스트하는 동안 내 경우에는 재정의 되지 arr않았습니다 arr[]. 동일한 키이지만 값이 다른 FormData에 여러 배열이 있습니다. 그래서 내가 가지고 arr값을 1다른 arr값으로 2.
Totoro

@Totoro 네, 맞아요, 내 실수. 나는 이것이 더 서버 측 관련 질문이라고 생각합니다. 다른 언어는 쿼리 문자열을 다르게 구문 분석 할 수 있습니다. 예를 들어 PHP는 설명한대로 동작하지만 arr배열에서도 작동하는 예제 (메모리가 Java에서 제공되는 경우)를 보았습니다 . 에서 이 주제에 이 질문에 대한 더 자세한 답이있다
올렉

사람이 객체의 배열을 게시하고자하는 경우 다음과 같이이 대답을 확장 할 수 있습니다for (var i = 0; i < myArr; i++) { var myItemInArr = myArr[i]; for (var prop in myItemInArr) { fileData.append(`myArr[${i}][${prop}]`, myItemInArr[prop]); } }
edqwerty

7

이것은 오래된 질문이지만 최근에 파일과 함께 객체를 게시하는 데이 문제가 발생했습니다. 객체와 배열 인 자식 속성을 사용하여 객체를 게시 할 수 있어야했습니다.

아래 함수는 개체를 살펴보고 올바른 formData 개체를 만듭니다.

// formData - instance of FormData object
// data - object to post
function getFormData(formData, data, previousKey) {
  if (data instanceof Object) {
    Object.keys(data).forEach(key => {
      const value = data[key];
      if (value instanceof Object && !Array.isArray(value)) {
        return this.getFormData(formData, value, key);
      }
      if (previousKey) {
        key = `${previousKey}[${key}]`;
      }
      if (Array.isArray(value)) {
        value.forEach(val => {
          formData.append(`${key}[]`, val);
        });
      } else {
        formData.append(key, value);
      }
    });
  }
}

이것은 다음 json을 변환합니다.

{
  name: 'starwars',
  year: 1977,
  characters: {
    good: ['luke', 'leia'],
    bad: ['vader'],
  },
}

다음 FormData에

 name, starwars
 year, 1977
 characters[good][], luke
 characters[good][], leia
 characters[bad][], vader

그것은 나에게 유용했고, append 내부의 값에 String (value)을 적용해야했습니다 (그렇지 않으면 true / false에 대해 실패합니다). 또한 (value !== null) && formData.append(key, value)그냥 formData.append(key, value)그렇지 않으면 null 값에서 실패합니다
Alexander

7

Typescript 버전 :

export class Utility {      
    public static convertModelToFormData(model: any, form: FormData = null, namespace = ''): FormData {
        let formData = form || new FormData();
        let formKey;

        for (let propertyName in model) {
            if (!model.hasOwnProperty(propertyName) || !model[propertyName]) continue;
            let formKey = namespace ? `${namespace}[${propertyName}]` : propertyName;
            if (model[propertyName] instanceof Date)
                formData.append(formKey, model[propertyName].toISOString());
            else if (model[propertyName] instanceof Array) {
                model[propertyName].forEach((element, index) => {
                    const tempFormKey = `${formKey}[${index}]`;
                    this.convertModelToFormData(element, formData, tempFormKey);
                });
            }
            else if (typeof model[propertyName] === 'object' && !(model[propertyName] instanceof File))
                this.convertModelToFormData(model[propertyName], formData, formKey);
            else
                formData.append(formKey, model[propertyName].toString());
        }
        return formData;
    }
}

사용 :

let formData = Utility.convertModelToFormData(model);

훌륭한 작업, 매우 유용합니다. : D
Cosimo Chellini

3

FormData에 모든 유형 입력 추가

const formData = new FormData();
for (let key in form) {
    Array.isArray(form[key])
        ? form[key].forEach(value => formData.append(key + '[]', value))
        : formData.append(key, form[key]) ;
}

2

중첩 된 개체와 배열이있는 경우 FormData 개체를 채우는 가장 좋은 방법은 재귀를 사용하는 것입니다.

function createFormData(formData, data, key) {
    if ( ( typeof data === 'object' && data !== null ) || Array.isArray(data) ) {
        for ( let i in data ) {
            if ( ( typeof data[i] === 'object' && data[i] !== null ) || Array.isArray(data[i]) ) {
                createFormData(formData, data[i], key + '[' + i + ']');
            } else {
                formData.append(key + '[' + i + ']', data[i]);
            }
        }
    } else {
        formData.append(key, data);
    }
}

1

다음 버전은 간단한 값을 포함하는 모델에 유효합니다.

function convertModelToFormData(val, formData = new FormData(), namespace = '') {
    if((typeof val !== 'undefined') && (val !== null)) {
        if(val instanceof Date) {
            formData.append(namespace, val.toISOString());
        } else if(val instanceof Array) {
            for(let element of val) {
                convertModelToFormData(element, formData, namespace + '[]');
            }
        } else if(typeof val === 'object' && !(val instanceof File)) {
            for (let propertyName in val) {
                if(val.hasOwnProperty(propertyName)) {
                    convertModelToFormData(val[propertyName], formData, namespace ? namespace + '[' + propertyName + ']' : propertyName);
                }
            }
        } else {
            formData.append(namespace, val.toString());
        }
    }
    return formData;
}

1

@YackY 대답 짧은 재귀 버전을 기반으로 :

function createFormData(formData, key, data) {
    if (data === Object(data) || Array.isArray(data)) {
        for (var i in data) {
            createFormData(formData, key + '[' + i + ']', data[i]);
        }
    } else {
        formData.append(key, data);
    }
}

사용 예 :

var data = {a: '1', b: 2, c: {d: '3'}};
var formData = new FormData();
createFormData(formData, 'data', data);

보낸 데이터 :

data[a]=1&
data[b]=2&
data[c][d]=3
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.