반응형

들어가며

calendar 프로젝트를 진행하면서 날짜 관련정보를 다루었다(Date 객체). 프로젝트 중에 날짜 관련 data를 쉽게 다룰수 있는 라이브러리를 발견하여 이에 대해서 간단히 정리해보고자 한다. Moment.JS 는 날짜(Date)형식의 데이터의 파싱, 검증, 조작 그리고 화면에 출력하는 작업을 위해 만들어진 아주 유용한 라이브러리이다.

프로젝트를 통해 느낀 Date object의 불편함 & Moment.JS의 편리함

Date object와 관련된 method를 사용하면서 불편한점이 많았다. 한가지 예를 들면 ISO 포맷형태의 날짜data(ex. 2017-01-25)를 얻기 위해서, 시간이 까지 포함된 ISOString형태(ex. 2017-01-25T12:25:00.000z)에서 T를 기준으로 split method를 사용하여 ISO 포맷형태의 날짜를 얻을수 있었다. 코드는 아래 와 같다.(바로 구하는 method는 없는것 같다.)

var d= new Date(); // 출력형태 Tue Feb 07 2017 23:25:32 GMT+0900 (KST) var ISOData = d.toISOString(); // 출력형태 2017-02-07T13:39:45.148Z var ISODate = ISOData.split("T",1); // 출력형태 2017-02-07

Date object를 사용하면서 부분적인 시간과 날짜 정보를 얻기 위해서 위와 같이 문자열을 쪼개어서 얻는것이 나이스(?)하지 못하다고 느꼈다. 위와 같은 코드를 Moment.js를 사용하여 구하려면 어떻게 하면 될까?

var ISODate = moment().format('YYYY[-]MM[-]DD');

위와 같이 보다 직관적인이고 간단한 코드를 통해서 ISO 포맷 형태의 날짜 정보를 얻을수 있다.

다른 예를 들자면 ISO 포맷형태의 TimeString간의 시간차이를 구하기 위해서는 내가 아는바로는 시간차이를 바로 구할수있는 method는 없었고, 역시 문자열 조작과 기존 Date object를 통해서 시간차이를 계산할수 있었다.

 

var time1 = "2017-02-01T12:25:00Z"

var time2 = "2017-02-04T12:20:00Z"

 

function dateFromISO(isostr) {

var parts = isostr.match(/\d+/g);

return new Date(parts[0], parts[1] - 1, parts[2], parts[3], parts[4], parts[5]);

};

 

var ParsedTime1= dateFromISO(time1);

var ParsedTime2= dateFromISO(time2);

var timeDifference = parsedTime2-parsedTime1 ; // 출력 단위 밀리초(ms)

 

위와 같이 정규표현식을 사용하여 기존ISOString 형태 시간 데이터를 쪼개어 배열에 저장하고, Date object를 통해서 시간정보로 가공하였다. 시간차이를 계산하기 위해서 이와같이 시간정보로 바꿔서 계산해야 한다.(이 역시 곧바로 구하는 method는 없는것 같다.) 위와 같은 함수를 생각해내지 못하면 해결(?)하지 못할수도 있다. 나이스(?)하지 못하다..

위와 같은 코드를 역시 Moment.JS를 사용하여 구하면 어떻게 될까?

 

var time1 = "2017-02-01T12:25:00Z"

var time2 = "2017-02-04T12:20:00Z"

var ms = moment(time2,"YYYY-MM-DDTHH:mm:ssZ").diff(moment(time1,"YYYY-MM-DDTHH:mm:ssZ")); // 출력 단위 밀리초(ms)

 

ISOstring형태의 시간정보를 다른 시간형태의 시간정보로 가공하지 않아도 되고, diff라는 method를 통해서 시간차이를 구하였다. 얼마나 직관적이고 간편한가!

나는 Javascript를 배우는 중이라서 다른 라이브러리를 사용하지 않은채 개발하였지만, 시간 관련 정보를 다루는 프로젝트를 개발하는 사람들에게 Moment.JS를 적극 추천한다.

Moment.JS의 method에는 많은것들이 있다. 이중에서 몇가지만 간단히 정리하고자 한다.

현재시간

현재시간을 얻기 위해서는 매개변수 없이 아래와 같이 호출하면 된다.

 

var now = moment();

 

문자열(String)을 통한 시간정보 생성

문자열(ex. "1989-03-15")을 통해서 시간을 생성하고자 할때는 아래와 같이 호출하면 된다.

 

var time = moment("2017-01-01");

 

위와 같이 " YYYY-MM-DD "형태의 string 외에도 " YYYY-MM-DD HH:MM:SS "등과 같은 형태의 시간문자열이 있을수 있다. 가능한 문자열 형태는 이 링크에서 확인하기를 바란다. 만약불가능한 형태의 시간 string이라면 아래 method를 사용하여 true , false 값으로 확인할수 있다.

 

var time = momnet("시간문자열").isValid(); //return true or false

 

정형화된 시간정보(Format Dates)

아래코드와 같이 자신이 원하는 형태의 시간정보를 생성할수 있다.

 

moment().format('MMMM Do YYYY, h:mm:ss a'); // February 8th 2017, 6:30:39 pm

moment().format('dddd'); // Wednesday

moment().format("MMM Do YY"); // Feb 8th 17

moment().format('YYYY [escaped] YYYY'); // 2017 escaped 2017

moment().format(); // 2017-02-08T18:30:39+09:00

 

상대적인 시간(Relative Time)

특정시간정보가 지금으로부터 어느정도의 시간거리를 가지고 있는지 알수 있다.

 

moment("20111031", "YYYYMMDD").fromNow(); // 5 years ago

moment("20120620", "YYYYMMDD").fromNow(); // 5 years ago

moment().startOf('day').fromNow(); // 19 hours ago

moment().endOf('day').fromNow(); // in 5 hours

moment().startOf('hour').fromNow(); // 34 minutes ago

 

달력관련 날짜 및 시간정보

 

moment().subtract(10, 'days').calendar(); // 01/29/2017

moment().subtract(6, 'days').calendar(); // Last Thursday at 6:36 PM

moment().subtract(3, 'days').calendar(); // Last Sunday at 6:36 PM

moment().subtract(1, 'days').calendar(); // Yesterday at 6:36 PM

moment().calendar(); // Today at 6:36 PM

moment().add(1, 'days').calendar(); // Tomorrow at 6:36 PM

moment().add(3, 'days').calendar(); // Saturday at 6:36 PM

moment().add(10, 'days').calendar(); // 02/18/2017

 

배열(Array)를 이용한 시간정보 생성

배열을 통해서 시간정보를 생성할수도 있다.

배열은 입력된 배열의 길이 만큼 앞에서부터 길이만큼 아래 배열에서 끊어서 의미를 확인하면된다.

[year, month, day, hour, minute, second, millisecond]

 

예제코드

moment([2010, 1, 14, 15, 25, 50, 125]); // February 14th, 3:25:50.125 PM

moment([2010]); // January 1st

moment([2010, 6]); // July 1st

moment([2010, 6, 10]); // July 10th

 

시간차이 계산

월차이를 구하는 코드 예제를 보자. 간편하다

 

moment('2016-06','YYYY-MM').diff('2015-01','month'); //17

 

여러가지 메소드와 경우의 수가 존재하므로 설명없이 예제코드들을 나열해보록 하겠다. 필요한 예제들만 골라서 사용하면 되겠다.(설명이 필요할것 같은 부분만 주석으로 설명하겠다.)

 

moment().format() //2017-02-08T18:44:10+09:00

moment().toString() //Wed Feb 08 2017 18:44:10 GMT+0900

moment('2013-11-16') - moment('2013-11-15') //86400000

moment().endOf('day') //1486565999999

 

var now = moment('2013-11-22'); //finish와 같은날로 지정

var start = moment('2013-11-10');

var finish = moment('2013-11-22');

var event = moment('2013-11-16').endOf('day'); //2013년 11월 16일의 끝나는 시점. 2013년 11월 16일 11시 59분 59초

 

event.diff(start) //604799999 event시점에서 start시점을 뺀 시간 단위 밀리초 (시간정보는 시간이 흐를수록 값이 커진다.)

event.diff(finish) //-432000001

 

moment().format('YYYY-MM-DD') //2017-02-08

moment().format('YYYY') //2017

moment().format('MM-DD') //02-08

moment(start).add('years',1).calendar() //11/10/2014 start시점에 1년을 더한다.

 

now.diff(start) > 0 && now.diff(finish) < 0 //false now시점이 start와 finish 사이에 있는지

 

moment('Tue Dec 23 12:02:08 EST 2014').format() //2014-12-24T02:02:08+09:00

moment().format('MMMM Do [at] h:mm:ss a') //February 8th at 6:44 pm [] 괄호로 감싸서 데이터 중간에 문자나 특수문자 입력가능

moment('2015/04/02 12:00').subtract('hours',9).format('YYYY/MM/DD hh:mm') // 2015/04/02 03:00 시점에서 9시간을 빼고 정해진 포맷대로 출력

 

moment('1/1/0001').format() // 2001-01-01T00:00:00+09:00

moment('0001-01-01').format() //0001-01-01T00:00:00+09:00

moment().format('MMMM D, YYYY') // February 8, 2017

 

now.isBetween(start, finish, '(]')) //true start 시점 < now시점 <= finish시점인지

 

위와 같이 몇가지만 간단히 정리해보았지만 여러가지 조합과 method가 있으니 더 많은 정보를 얻고자 하는 사람은 아래 사이트를 참고하길 바란다.

 

https://momentjs.com

 

Moment.js | Home

Format Dates moment().format('MMMM Do YYYY, h:mm:ss a'); moment().format('dddd'); moment().format("MMM Do YY"); moment().format('YYYY [escaped] YYYY'); moment().format(); Relative Time moment("20111031", "YYYYMMDD").fromNow(); moment("20120620", "YYYYMMDD"

momentjs.com

출처: https://github.com/jinyowo/JS-Calendar/wiki/**-moment.js-(%EB%82%A0%EC%A7%9C%EA%B4%80%EB%A0%A8-%EC%9E%91%EC%97%85%EC%9D%84-%EC%9C%84%ED%95%9C-%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%EB%9D%BC%EC%9D%B4%EB%B8%8C%EB%9F%AC%EB%A6%AC)

반응형
반응형

VueJS and Axios GitHub – axios/axios: Promise based HTTP client for the browser and node.js work beautifully together for making HTTP requests. However, uploading files with VueJS and Axios can be a little bit challenging since it requires uploading files through an AJAX type system. I’ll be honest, I hate doing file uploads, but they are a necessity for the majority of applications. This tutorial should be a quick start guide on the process and a few tips I’ve learned when handling file uploads to make your life a little easier.

Prerequisites

In this tutorial I’m going to be using Axios v0.16.2 and VueJS v2.1.0 for doing the file uploads. On the back end you can use the framework that you want, or language that you want. I’ll talk about using PHP/Laravel to process files and more or less pseudo-code the backend process. The biggest take aways will be how to do the uploading of the file with VueJS and Axios.

I’m also going to assume you are using a modern browser that supports the FormData object: FormData – Web APIs | MDN. This is what makes the process a whole heck of a lot easier.

Uploading a Single File

So first, we will start with a single file to get things going. I just built a simple component that contains a file input:

<template> <div class="container"> <div class="large-12 medium-12 small-12 cell"> <label>File <input type="file" id="file" ref="file" v-on:change="handleFileUpload()"/> </label> <button v-on:click="submitFile()">Submit</button> </div> </div> </template>

If you take a look at the input[type="file"] I added a few attributes. The first is a ref attribute that gives this input a name. We can now access this input from within VueJS which we will in a second.

The next is the v-on:change="handleFileUpload()" attribute. When the user uploads a file, this gets called and we can handle the file. We will be implementing this method in the next step.

The last element in the simple form is a button that calls a method submitFile() when clicked. This is where we will submit our file to the server and we will be implementing this method as well.

 

Handle User File Upload

The first thing we want to do is add the handleFileUpload() method to our methods object which will give us a starting point for implementation:

<script> export default { methods: { handleFileUpload(){ } } } </script>

What we will do in this method is set a local variable to the value of the file uploaded. Now since we are using a modern browser, this will be a FileList object: FileList – Web APIs | MDN which contains File objects: File – Web APIs | MDN. The FileList is not directly editable by the user for security reasons. However, we can allow users to select and de-select files as needed, which we will go through later in the tutorial.

Since we are setting a local piece of data, let’s add that right now to our Vue component. In our data() method add:

data(){ return { file: '' } },

Now we have something to set in our handleFileUpload() method! Let’s go back and add the following code to the handleFileUpload() method:

methods: { handleFileUpload(){ this.file = this.$refs.file.files[0]; } }

What this does is when the file has been changed, we set the local file variable to the first File object in the FileList on the input[type="file"]. The this.$refs.file refers to the ref attribute on the the input[type="file"]. This makes it easily accessible within our component.

Submit To Server Through Axios

Now it’s time to submit our file through the server through Axios! On our button, we have a submitFile() method we need to implement, so let’s add this to our methods:

submitFile(){ },

Now this is where we implement our axios request.

The first thing we need to do is implement a FormData object like this:

let formData = new FormData();

Next, what we will do is append the file to the formData. This is done through the append() method on the object: FormData.append() – Web APIs | MDN. What we are doing is essentially building a key-value pair to submit to the server like a standard POST request:

formData.append('file', this.file);

We just append the file variable that we have our data stored in. Now I’m not going to go into validations, but before we go any further, if you were to put this in production and the file needed to be added, I’d add a validation here to make sure the file variable contains an actual file.

Now we can begin to make our axios request! We will be doing this through the post() method. If you look at their API (GitHub – axios/axios: Promise based HTTP client for the browser and node.js), you see the post() method contains 3 parameters. The third parameter is a config for the request which is awesome because we can add other headers to it.

Our completed request should look like:

axios.post( '/single-file', formData, { headers: { 'Content-Type': 'multipart/form-data' } } ).then(function(){ console.log('SUCCESS!!'); }) .catch(function(){ console.log('FAILURE!!'); });

The first parameter is the URL we will be POSTing to. For this example, I have a URL set up on my server which is /single-file. The next parameter is a key-value store of the data we are passing. This is our FormData() which we built to have our file. The third parameter is probably the key to making this all work. This is adding the multipart/form-data header we need to send the file to the server.

If you are used to file uploading, this is usually an attribute on the form you are submitting like <form enctype="multipart/form-data"></form>. Without this header, the POST request will ignore the file.

Now with the rest of our request, we process a callback method on a successful request which can be used to display a notification and we process a callback on failure which can be used to alert the user of an unsuccessful upload.

On the server side, you can access the file through the key of file which is the first parameter of the formData.append('file', this.file); method.

In PHP it’d be: $_FILES['file'] and in Laravel, you can use the Request facade and access it through Request::file('files') and do whatever server side processing you need.

Our SingleFile.vue component used for testing looks like this:

<template> <div class="container"> <div class="large-12 medium-12 small-12 cell"> <label>File <input type="file" id="file" ref="file" v-on:change="handleFileUpload()"/> </label> <button v-on:click="submitFile()">Submit</button> </div> </div> </template> <script> export default { /* Defines the data used by the component */ data(){ return { file: '' } }, methods: { /* Submits the file to the server */ submitFile(){ /* Initialize the form data */ let formData = new FormData(); /* Add the form data we need to submit */ formData.append('file', this.file); /* Make the request to the POST /single-file URL */ axios.post( '/single-file', formData, { headers: { 'Content-Type': 'multipart/form-data' } } ).then(function(){ console.log('SUCCESS!!'); }) .catch(function(){ console.log('FAILURE!!'); }); }, /* Handles a change on the file upload */ handleFileUpload(){ this.file = this.$refs.file.files[0]; } } } </script>

The next section, we will handle multiple files. This isn’t anything super different, but I’ll point out the changes!

Uploading Multiple Files

Handling multiple files is very similar to a single file. What we will do is begin with a template that looks like this in our Vue component:

<template> <div class="container"> <div class="large-12 medium-12 small-12 cell"> <label>Files <input type="file" id="files" ref="files" multiple v-on:change="handleFileUploads()"/> </label> <button v-on:click="submitFiles()">Submit</button> </div> </div> </template>

Besides the ref attribute name change and the id changing to files, the most important attribute is we added multiple to our input[type="file”]. This allows the user to cmd (ctrl) + click to select multiple files at once. A super slick way to upload files. In the next section we will be allowing the user to remove files and select more files if they made a mistake 😉 but for now, it’s super slick.

 

Multiple File handleFileUploads() method

This is very similar to an individual file, except we will be adding all of the files to our array if the user selects more than one. First, let’s add our data store to our Vue component and give it variable named files:

/* Defines the data used by the component */ data(){ return { files: '' } },

Now we have a local variable to store our files to. We can now do our handleFileUploads() method:

/* Handles a change on the file upload */ handleFilesUpload(){ this.files = this.$refs.files.files; }

What this does is grab all of the files in the FilesList from our files upload and stores it locally.

Implement submitFiles() method

We are ready to submit all of our files to the server now! First, let’s add our submitFiles() method to the methods array:

/* Submits all of the files to the server */ submitFiles(){ },

Like in the last method, we will initialize the FormData() object first:

/* Initialize the form data */ let formData = new FormData();

Now, what we will do is loop over all of the files selected and add them to the files array we are going to submit to the server. The files array will be a key in the formData() object we will be sending to the server:

/* Iteate over any file sent over appending the files to the form data. */ for( var i = 0; i < this.files.length; i++ ){ let file = this.files[i]; formData.append('files[' + i + ']', file); }

We are now ready to send our files to the server through Axios:

/* Make the request to the POST /multiple-files URL */ axios.post( '/multiple-files', formData, { headers: { 'Content-Type': 'multipart/form-data' } } ).then(function(){ console.log('SUCCESS!!'); }) .catch(function(){ console.log('FAILURE!!'); });

There we go! Now we are allowing users to upload multiple files using Axios and VueJS through an AJAX call.

On the server side, you can access the files through the key of files which is the first parameter of the formData.append('files[' + i + ']', file); method.

In PHP it’d be: $_FILES['files'] and in Laravel, you can use the Request facade and access it through Request::file('files') and do whatever server side processing you need. You can loop through all of the files now to allow for multiple uploads.

Our MultipleFiles.vue component should look like:

<template> <div class="container"> <div class="large-12 medium-12 small-12 cell"> <label>Files <input type="file" id="files" ref="files" multiple v-on:change="handleFilesUpload()"/> </label> <button v-on:click="submitFiles()">Submit</button> </div> </div> </template> <script> export default { /* Defines the data used by the component */ data(){ return { files: '' } }, methods: { /* Submits all of the files to the server */ submitFiles(){ /* Initialize the form data */ let formData = new FormData(); /* Iteate over any file sent over appending the files to the form data. */ for( var i = 0; i < this.files.length; i++ ){ let file = this.files[i]; formData.append('files[' + i + ']', file); } /* Make the request to the POST /multiple-files URL */ axios.post( '/multiple-files', formData, { headers: { 'Content-Type': 'multipart/form-data' } } ).then(function(){ console.log('SUCCESS!!'); }) .catch(function(){ console.log('FAILURE!!'); }); }, /* Handles a change on the file upload */ handleFilesUpload(){ this.files = this.$refs.files.files; } } } </script>

The next step we will allow users to edit the files they have selected so they don’t accidentally upload a file they don’t want.

Allowing Users to Edit Selected Files Before Uploading

When uploading multiple files, it’s very common that you accidentally select a file you do NOT want to upload. This sounds simple enough to resolve until you find out you can’t directly edit the FileList object for security reasons. However, you can transform it and edit the new list as an array and allow users to change the files they want uploaded.

First, let’s reuse the template from the multiple files component:

<template> <div class="container"> <div class="large-12 medium-12 small-12 cell"> <label>Files <input type="file" id="files" ref="files" multiple v-on:change="handleFilesUpload()"/> </label> <button v-on:click="submitFiles()">Submit</button> </div> </div> </template>

Hide File Input

The first thing we will do is hide the actual file input. This is because we will be making a simple design interface to allow users to select the files they want. I just added a style tag that moves the input off of the screen. This is because it’s a security issue to trigger a click on the hidden file input.

<style> input[type="file"]{ position: absolute; top: -500px; } </style>

Next, I added a button that triggers a click on the input:

<div class="large-12 medium-12 small-12 cell"> <button v-on:click="addFiles()">Add Files</button> </div>

So when this is clicked, we trigger a click on the file element. We need to implement the addFiles() method in our Vue component like this:

addFiles(){ this.$refs.files.click(); }

This will fire a click on the files input and the user will be prompted with a file selection box where they can select the files we want.

Implement handleFilesUpload()

This is where things get a little bit different. Like the first two examples, we will add a local variable to add files to:

data(){ return { files: [] } },

We want this as an array so we can push files onto it.

Now, when the user selects some files to upload, we will push them on our local files variable:

let uploadedFiles = this.$refs.files.files; /* Adds the uploaded file to the files array */ for( var i = 0; i < uploadedFiles.length; i++ ){ this.files.push( uploadedFiles[i] ); }

We do this through a loop instead of pushing the entire chunk onto the files array because otherwise we’d have groups based on what was selected. You can add validations here as well so the user doesn’t upload the same file multiple times if you want as well.

Display Currently Uploaded Files

In this use case, we want users to remove files they updated by accident, so we need to display the currently uploaded files.

To do that, we will head back into our template and add the following code:

<div class="large-12 medium-12 small-12 cell"> <div v-for="(file, key) in files" class="file-listing">{{ file.name }} <span class="remove-file" v-on:click="removeFile( key )">Remove</span></div> </div> <br>

What this does is iterate over all of the files we’ve currently added and displays them to the user. A couple things to note.

First, the v-for="(file, key) in files". What this does is iterate over the files that we’ve uploaded and grabs the key which is the index of the file in the files array and the file itself. We then display the name of the file with: {{ file.name }} which is part of the individual file object. There’s more information in the object which is documented here: File – Web APIs | MDN

Next, we add a removeFile(key) method which will remove the file from the file array. When the file is removed, the reactive nature of VueJS will update our listing.

Implement removeFile() Method

This method will remove the file from our uploaded files array. First, let’s add the method to our methods array:

removeFile( key ){ }

The method accepts the key in the files array of the file we are removing. The full implementation of this method will be:

removeFile( key ){ this.files.splice( key, 1 ); }

What this does is splice the files array at the index of the file we are removing and remove 1 entry from the array. When we do this, our list will re-render through VueJS keeping everything in sync. Since we are using a local files array, we can modify this at will. The next and final thing we have to do is submit our files to the server that the user has selected!

Submit Files To Server

From here, we’ve allowed the user to modify the files they have selected, we just have to allow them to submit to the server for processing.

First, let’s add the submitFiles() method to our methods object:

submitFiles(){ }

Like the rest of the examples, let’s first create our FormData() object:

/* Initialize the form data */ let formData = new FormData();

Now, let’s add all of the chosen files to the form data:

/* Iterate over any file sent over appending the files to the form data. */ for( var i = 0; i < this.files.length; i++ ){ let file = this.files[i]; formData.append('files[' + i + ']', file); }

This iterates over the files that the user has selected and prepares to submit them to the server.

Now, we can run the axios.post() method to submit the files to our endpoint:

axios.post( '/select-files', formData, { headers: { 'Content-Type': 'multipart/form-data' } } ).then(function(){ console.log('SUCCESS!!'); }) .catch(function(){ console.log('FAILURE!!'); });

This sends all of our form data to the server with the files that the user has uploaded! If you were to run this as an example, you can see that after you remove a file, it’s no longer sent to the server.

Like before, on the server side, you can access the files through the key of files which is the first parameter of the formData.append('files[' + i + ']', file); method.

When using Laravel and the Request facade, you can access the selected files the user has uploaded with the following method: Request::file('files'). In straight up PHP it’d be $_FILES['files']. You can now do any processing you want!

Our SelectFiles.vue component should look like:

<style> input[type="file"]{ position: absolute; top: -500px; } div.file-listing{ width: 200px; } span.remove-file{ color: red; cursor: pointer; float: right; } </style> <template> <div class="container"> <div class="large-12 medium-12 small-12 cell"> <label>Files <input type="file" id="files" ref="files" multiple v-on:change="handleFilesUpload()"/> </label> </div> <div class="large-12 medium-12 small-12 cell"> <div v-for="(file, key) in files" class="file-listing">{{ file.name }} <span class="remove-file" v-on:click="removeFile( key )">Remove</span></div> </div> <br> <div class="large-12 medium-12 small-12 cell"> <button v-on:click="addFiles()">Add Files</button> </div> <br> <div class="large-12 medium-12 small-12 cell"> <button v-on:click="submitFiles()">Submit</button> </div> </div> </template> <script> export default { /* Defines the data used by the component */ data(){ return { files: [] } }, /* Defines the method used by the component */ methods: { /* Adds a file */ addFiles(){ this.$refs.files.click(); }, /* Submits files to the server */ submitFiles(){ /* Initialize the form data */ let formData = new FormData(); /* Iteate over any file sent over appending the files to the form data. */ for( var i = 0; i < this.files.length; i++ ){ let file = this.files[i]; formData.append('files[' + i + ']', file); } /* Make the request to the POST /select-files URL */ axios.post( '/select-files', formData, { headers: { 'Content-Type': 'multipart/form-data' } } ).then(function(){ console.log('SUCCESS!!'); }) .catch(function(){ console.log('FAILURE!!'); }); }, /* Handles the uploading of files */ handleFilesUpload(){ let uploadedFiles = this.$refs.files.files; /* Adds the uploaded file to the files array */ for( var i = 0; i < uploadedFiles.length; i++ ){ this.files.push( uploadedFiles[i] ); } }, /* Removes a select file the user has uploaded */ removeFile( key ){ this.files.splice( key, 1 ); } } } </script>

There ya go! You can now allow users to adjust their mistakes if they select a file they don’t want to upload.

Gotchas and Recommendations

A few things to point out when uploading using FormData.

Adding additional POST data to the Request

You can always include more information than just files with your post. When you build your FormData you can add additional text or other fields like this:

/* Initialize the form data */ let formData = new FormData(); /* Iteate over any file sent over appending the files to the form data. */ for( var i = 0; i < this.files.length; i++ ){ let file = this.files[i]; formData.append('files[' + i + ']', file); } /* Additional POST Data */ formData.append('first_name', 'Dan'); formData.append('last_name', 'Pastori');

The first_name and last_name fields will be accessible on the server just like a normal post request!

 

Arrays with FormData()

Now since we are configuring our request before we send it to the sever, arrays get accessed differently. You will either need to account for this when building your FormData object. In VueJS, when working with arrays, you can’t just do:

this.coolData = ['one', 'two', 'three']; formData.append('cool_data', this.coolData);

or you will get an [object Object] on the server side. You can either iterate over your cool data and push it on a nicely organized array or you can do a JSON.stringify() method on the data which will convert it to JSON before sending it to the server.

this.coolData = ['one', 'two', 'three']; formData.append('cool_data', JSON.stringify( this.coolData ) );

You will just need to decode it before you can access it. In PHP, that method would be json_decode($json).

Clearing local files on success

When axios returns success, another quick tip is to reset your local files array back to nothing. This makes sure that if you are doing things in a single page application type way or any AJAX driven way, the user who initially submitted the files doesn’t try to re-send a different group of files and gets the first group of files that still exist in the array sent along as well. You can simply clear your local files like this:

this.files = '';

Conclusion

After running through this a few times, uploading files with VueJS and Axios through AJAX becomes a little easier to grasp! Hopefully this tutorial has helped a little. There is always room for expansion and you can do progress uploads and other cool features.

This type of file uploading process comes in handy when developing an API Driven Application, especially when using VueJS. We are working on a book that will tie in this feature along with a whole bunch more API Driven ideals. We will go start to implementation to launch of an API Driven Application and point out common gotchas and tips. Sign up here to stay in the loop as the book progresses: Server Side Up General List

반응형
반응형

Component 를 Link to 로 연결시에 스크롤이 0 으로 이동되도록 아래와 같이 처리

 

반응형
반응형


해결법은 매우 간단했다.

venv VM폴더를 밀어버리고..... 


virtualenv 로 새로 폴더 생성하고 가상환경 들어가서 pip install -r requirement.txt 하면 된다.

원인으로는 가상환경에서 본래 파이썬 경로를 인지하고 있는데, 

다른 개발 환경에서 파이썬을 나처럼 다른 경로에 지정을 한 경우 발생한다. ㅠㅠ 


반응형

'웹프로그래밍 > Python' 카테고리의 다른 글

Python whl 파일 설치 방법  (0) 2018.12.08
반응형

1. Python whl 파일 설치 방법

1) 설치하고자 하는 whl 파일을 다운로드 받는다.

2) python -m pip install whl파일명


2. Beautifulsoup 설치 방법

1) https://pypi.python.org/pypi/beautifulsoup4 여기서 관련 whl 파일을 다운로드 한다.

2) 아래 해당 명령어를 console에서 실행한다.

python -m pip install beautifulsoup4-4.4.1-py2-none-any.whl 

3) 정상 설치 여부를 확인한다.

>>> import bs4
>>> bs4

>>> from bs4 import BeautifulSoup
>>> soup = BeautifulSoup("data", "html.parser")
>>> soup
data
>>> soup.prettify()
'\n data\n'

4) 위와 같이 출력 되면 정상적으로 설치가 완료된 것이다.

3. Python OpenSSL 설치 방법

1) Windows7에 설치시 Service Pack 1을 설치한 상태에서 진행해야 한다.

2) CMD 창에 easy_install pyopenssl 입력 한다.

3) 관련 로그가 나오구 특별한 사항이 없다면 정상설치 된 것이다.

4) 설치도중 VC++ 관련 오류가 나올경우 아래 경로에서 VC++관련 정보를 다운로드 하여 설치한다.
    https://www.microsoft.com/en-us/download/details.aspx?id=44266

4. PIP로 설치가 안될경우 설치 방법

1) easy_install pyopenssl

2) easy_install beautifulsoup

3) easy_install Scrapy
    Scrapy로 설치시 twisted관련 오류가 발생할 경우 아래 zope.interface를 추가로 설치한다.

4) easy_install zope.interface


5. PIP 최신 버전 업그레이드 방법

1) python -m pip install --upgrade pip


6. Python IDE 무료 툴

1) 기능은 제한되어 있지만 무료로 쓸수 있는 Community 버전으로 다운로드 한다.


7. pip로 관련 모듈 업그레이드 안되고 아래 오류등이 나올경우 조치 사항

1) 오류 메세지 종류 pip install scrapy만 실행시 아래 와 같은 메세지 노출될경우

Could not find a version that satisfies the requirement scrapy (from versions:)
No matching distribution found for scrapy

2) 좀더 정확한 오류 메세지를 확인하기 위해 아래 명령어를 추가로 실행 pip -vvv install scrapy

 Could not fetch URL https://pypi.python.org/simple/scrapy/: 
 connection error: SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:590) - skippig

위와 같이 SSL관련 인증이 문제일경우 해당 site를 신뢰 할 수 있게 설정해서 PIP를 실행하면 됨.

pip install --upgrade --trusted-host pypi.python.org 설치하고자 하는 ex) pip install --upgrade --trusted-host pypi.python.org scrapy



출처: http://bobr2.tistory.com/entry/Python-whl-파일-설치-방법 [나만의공간]

반응형

'웹프로그래밍 > Python' 카테고리의 다른 글

Could not import runpy module  (0) 2018.12.08
반응형

*.ts 로 작업을 시작할때..

require 를 사용하면 아래와 같은 오류가 발생할 수 있다.


require is not defined in typescript


그럴땐 아래와 같이 npm 패키지를 설치해주자.


npm install @types/node

반응형
반응형

mcrypt_* 이 PHP 7.1 에서 deprecated 이 되었고, PHP7.2 에서 mcrypt_* 이 삭제되어 사용이 불가능 해졌다.

대신 openssl encrypt 를 사용하면 된다. 


private static $key = "key_pass";
private static $cipher = "aes-256-cbc";

public static function encrypt($buffer){
$ivlen = openssl_cipher_iv_length(self::$cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
return openssl_encrypt($buffer, self::$cipher, self::$key, $options=0, $iv, $tag);
}

public static function decrypt($buffer){
$ivlen = openssl_cipher_iv_length(self::$cipher);
$iv = openssl_random_pseudo_bytes($ivlen);
return openssl_decrypt($buffer, self::$cipher, self::$key, $options=0, $iv, $tag);
}


반응형
반응형

VC9 : IIS 용

[Thread Safe 와 Non Thread Safe]

 

우선 윈도우용 PHP는 항상 Thread Safe 버전으로 나왔었습니다.
이유는 윈도우가 멀티쓰레드 방식인데 PHP 는 멀티프로세스 방식으로 개발 되었기 때문이죠.
참고로 리눅스나 유닉스는 원래 멀티프로세스 방식이었기에 문제가 되지 않았습니다.

PHP를 IIS와 연동하기 위해 CGI 또는 ISAPI 방식으로 연동을 합니다.
그런데 PHP와 관련된 모듈들이 대부분 멀티프로세스 방식으로 개발 되었기 때문에
멀티쓰레드 방식으로 개발된 ISAPI 로 연동하였을 경우 서버가 다운되는 현상이 나타났습니다.

그래서 안정적인 방법으로 CGI 방식을 사용하긴 하지만 이 것 역시 퍼포먼스 측면에서 너무 느리다는게 문제가 되었죠.
이 퍼포먼스 문제를 개선한 것이 Non Thread Safe 버전이라고 생각하시면 되겠습니다…^^

그럼 결론적으로 아래와 같은 조합이라 생각할 수 있겠죠? ^^a

 

Windows + IIS(ISAPI) : VC9 Thread Safe 버전
Windows + IIS(CGI or FastCGI) : VC9 Non Thread Safe 버전
Windows + Apache(MPM worker) : VC6 Thread Safe 버전
Windows + Apache(MPM prefork) : VC6 Non Thread Safe 버전

 

출처 : http://auctionpro.co.kr/?p=773

반응형

+ Recent posts