avatarJake Simmons

Free AI web copilot to create summaries, insights and extended knowledge, download it at here

7759

Abstract

component template how the upload blue button and the invisible file input are linked. When the user clicks on the blue button, a click handler triggers the file input via <code>fileUpload.click()</code>.</p><p id="ac29">The user will then choose a file from the file upload dialog, and the <code>change</code> event will be triggered and handled by <code>onFileSelected()</code>.</p><h1 id="7571">Uploading a file to the backend using the Angular HTTP Client</h1><p id="fff6">Let’s now have a look at our component class and the implementation of <code>onFileSelected()</code>:</p><div id="98fa"><pre><span class="hljs-meta">@Component</span>({ <span class="hljs-attr">selector</span>: <span class="hljs-string">'file-upload'</span>, <span class="hljs-attr">templateUrl</span>: <span class="hljs-string">"file-upload.component.html"</span>, <span class="hljs-attr">styleUrls</span>: [<span class="hljs-string">"file-upload.component.scss"</span>] }) <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">FileUploadComponent</span> {

fileName = <span class="hljs-string">''</span>;

<span class="hljs-title function_">constructor</span>(<span class="hljs-params"><span class="hljs-keyword">private</span> http: HttpClient</span>) {}

<span class="hljs-title function_">onFileSelected</span>(<span class="hljs-params">event</span>) {

    <span class="hljs-keyword">const</span> <span class="hljs-attr">file</span>:<span class="hljs-title class_">File</span> = event.<span class="hljs-property">target</span>.<span class="hljs-property">files</span>[<span class="hljs-number">0</span>];

    <span class="hljs-keyword">if</span> (file) {

        <span class="hljs-variable language_">this</span>.<span class="hljs-property">fileName</span> = file.<span class="hljs-property">name</span>;

        <span class="hljs-keyword">const</span> formData = <span class="hljs-keyword">new</span> <span class="hljs-title class_">FormData</span>();

        formData.<span class="hljs-title function_">append</span>(<span class="hljs-string">"thumbnail"</span>, file);

        <span class="hljs-keyword">const</span> upload$ = <span class="hljs-variable language_">this</span>.<span class="hljs-property">http</span>.<span class="hljs-title function_">post</span>(<span class="hljs-string">"/api/thumbnail-upload"</span>, formData);

        upload$.<span class="hljs-title function_">subscribe</span>();
    }
}

}</pre></div><p id="efe8">Here is what is going in this component:</p><ul><li>we are getting a reference to the files that the user selected by accessing the <code>event.target.files</code> property.</li><li>we then build a form payload by using the <code>FormData</code> API. This is a standard browser API, it's not Angular-specific.</li><li>we then use the Angular HTTP client to create an HTTP request and send the file to the backend</li></ul><p id="8224">At this point, we would already have a working file upload component. But we want to take this component one step further. We want to be able to display a progress indicator to the user, and also support upload cancelation.</p><h1 id="2e9b">How to Display a File Upload Progress Indicator</h1><p id="0abb">We are going to add a few more elements to the UI of our file upload component. Here is the final version of the file upload component template:</p><div id="2cff"><pre><input <span class="hljs-keyword">type</span>=<span class="hljs-string">"file"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"file-input"</span> [accept]=<span class="hljs-string">"requiredFileType"</span> (change)=<span class="hljs-string">"onFileSelected($event)"</span> #fileUpload>

<span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"file-upload"</span>></span>

{{fileName || "No file uploaded yet."}}

<span class="hljs-tag">&lt;<span class="hljs-name">button</span> <span class="hljs-attr">mat-mini-fab</span> <span class="hljs-attr">color</span>=<span class="hljs-string">"primary"</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"upload-btn"</span>
  (<span class="hljs-attr">click</span>)=<span class="hljs-string">"fileUpload.click()"</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">mat-icon</span>&gt;</span>attach_file<span class="hljs-tag">&lt;/<span class="hljs-name">mat-icon</span>&gt;</span>

<span class="hljs-tag">&lt;/<span class="hljs-name">button</span>&gt;</span>

<span class="hljs-tag"></<span class="hljs-name">div</span>></span></span>

<span class="language-xml"><span class="hljs-tag"><<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"progress"</span>></span>

<span class="hljs-tag"><<span class="hljs-name">mat-progress-bar</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"progress-bar"</span> <span class="hljs-attr">mode</span>=<span class="hljs-string">"determinate"</span> [<span class="hljs-attr">value</span>]=<span class="hljs-string">"uploadProgress"</span> *<span class="hljs-attr">ngIf</span>=<span class="hljs-string">"uploadProgress"</span>></span>

<span class="hljs-tag"></<span class="hljs-name">mat-progress-bar</span>></span>

<span class="hljs-tag"><<span class="hljs-name">mat-icon</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"cancel-upload"</span> (<span class="hljs-attr">click</span>)=<span class="hljs-string">"cancelUpload()"</span> *<span class="hljs-attr">ngIf</span>=<span class="hljs-string">"uploadProgress"</span>></span>delete_forever<span class="hljs-tag"></<span class="hljs-name">mat-icon</span>></span>

<span class="hljs-tag"></<span class="hljs-name">div</span>></span></span></pre></div><p id="6548">The two main elements that we have added to the UI are:</p><ul><li>An Angular Material progress bar, which is visible only while the file upload is still in progress.</li><li>A cancel upload button, also only visible when an upload is still ongoing</li></ul><h2 id="8e22">How to know how much of the file has been uploaded?</h2><p id="318b">The way that we implement the progress indicator, is by using the <code>reportProgress</code> feature of the Angular HTTP client.</p><p id="7c34">With this feature, we can get notified of the progress of a file upload via multiple events emitted by the HTTP Observable.</p><p id="8436">To see it in action, let’s have a look at the final version of the file upload component class, with all its features implemented:</p><div id="88a0"><pre><span class="hljs-meta">@Component</span>({ <span class="hljs-attr">selector</span>: <span class="hljs-string">'file-upload'</span>, <span class="hljs-attr">templateUrl</span>: <span class="hljs-string">"file-upload.component.html"</span>, <span class="hljs-attr">styleUrls</span>: [<span class="hljs-string">"file-upload.component.scss"</span>] }) <span class="hljs-keyword">export</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">FileUploadComponent</span> {

<span class="hljs-meta">@Input</span>()
<span class="hljs-attr">requiredFileType</span>:<span class="hljs-built_in">string</span>;

fileName = <span class="hljs-string">''</span>;
<span class="hljs-attr">uploadProgress</span>:<span class="hljs-built_in">number</span>;
<span class="hljs-attr">uploadSub</span>: <span class="hljs-title class_">Subscription</span>;

<span class="hljs-title function_">constructor</span>(<span class="hljs-

Options

params"><span class="hljs-keyword">private</span> http: HttpClient</span>) {}

<span class="hljs-title function_">onFileSelected</span>(<span class="hljs-params">event</span>) {
    <span class="hljs-keyword">const</span> <span class="hljs-attr">file</span>:<span class="hljs-title class_">File</span> = event.<span class="hljs-property">target</span>.<span class="hljs-property">files</span>[<span class="hljs-number">0</span>];
  
    <span class="hljs-keyword">if</span> (file) {
        <span class="hljs-variable language_">this</span>.<span class="hljs-property">fileName</span> = file.<span class="hljs-property">name</span>;
        <span class="hljs-keyword">const</span> formData = <span class="hljs-keyword">new</span> <span class="hljs-title class_">FormData</span>();
        formData.<span class="hljs-title function_">append</span>(<span class="hljs-string">"thumbnail"</span>, file);

        <span class="hljs-keyword">const</span> upload$ = <span class="hljs-variable language_">this</span>.<span class="hljs-property">http</span>.<span class="hljs-title function_">post</span>(<span class="hljs-string">"/api/thumbnail-upload"</span>, formData, {
            <span class="hljs-attr">reportProgress</span>: <span class="hljs-literal">true</span>,
            <span class="hljs-attr">observe</span>: <span class="hljs-string">'events'</span>
        })
        .<span class="hljs-title function_">pipe</span>(
            <span class="hljs-title function_">finalize</span>(<span class="hljs-function">() =&gt;</span> <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">reset</span>())
        );
      
        <span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadSub</span> = upload$.<span class="hljs-title function_">subscribe</span>(<span class="hljs-function"><span class="hljs-params">event</span> =&gt;</span> {
          <span class="hljs-keyword">if</span> (event.<span class="hljs-property">type</span> == <span class="hljs-title class_">HttpEventType</span>.<span class="hljs-property">UploadProgress</span>) {
            <span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadProgress</span> = <span class="hljs-title class_">Math</span>.<span class="hljs-title function_">round</span>(<span class="hljs-number">100</span> * (event.<span class="hljs-property">loaded</span> / event.<span class="hljs-property">total</span>));
          }
        })
    }
}

<span class="hljs-title function_">cancelUpload</span>(<span class="hljs-params"></span>) { <span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadSub</span>.<span class="hljs-title function_">unsubscribe</span>(); <span class="hljs-variable language_">this</span>.<span class="hljs-title function_">reset</span>(); }

<span class="hljs-title function_">reset</span>(<span class="hljs-params"></span>) { <span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadProgress</span> = <span class="hljs-literal">null</span>; <span class="hljs-variable language_">this</span>.<span class="hljs-property">uploadSub</span> = <span class="hljs-literal">null</span>; } }</pre></div><p id="6e91">As we can see, we have set the <code>reportProgress</code> property to true in our HTTP call, and we have also set the <code>observe</code> property to the value <code>events</code>.</p><p id="cbac">This means that, as the POST call continues, we are going to receive event objects reporting the progress of the HTTP request.</p><p id="294a">These events will be emitted as values of the <code>http</code> Observable, and come in different types:</p><ul><li>events of type <code>UploadProgress</code> report the percentage of the file that has already been uploaded</li><li>events of types <code>Response</code> report that the upload has been completed</li></ul><p id="aa3c">Using the events of type <code>UploadProgress</code>, we are saving the ongoing upload percentage in a member variable <code>uploadProgress</code>, which we then use to update the value of the progress indicator bar.</p><p id="ea5b">When the upload either completes or fails, we need to hide the progress bar from the user.</p><p id="b2ef">We can make sure that we do so by using the RxJs <code>finalize</code> operator, which is going to call the <code>reset()</code> method in both cases: upload success or failure.</p><h1 id="29cb">How to Cancel an Ongoing File Upload</h1><p id="d74e">In order to support file upload cancellation, all we have to is keep a reference to the RxJs Subscription object that we get when the <code>http</code> Observable gets subscribed to.</p><p id="aa0f">In our component, we store this subscription object in the <code>uploadSub</code> member variable.</p><p id="5ae9">While the upload is still in progress, the user might decide to cancel it by clicking on the cancel button. Then the <code>cancelUpload()</code> upload method is going to get triggered and the HTTP request can be canceled by unsubscribing from the <code>uploadSub</code> subscription.</p><p id="5e61">This unsubscription will trigger the immediate cancelation of the ongoing file upload.</p><h1 id="9aad">How to accept only files of a certain type</h1><p id="c8b0">In the final version of our file upload component, we can require the user to upload a file of a certain type, by using the <code>requiredFileType</code> property:</p><div id="8c53"><pre><span class="hljs-tag"><<span class="hljs-name">file-upload</span> <span class="hljs-attr">requiredFileType</span>=<span class="hljs-string">"image/png"</span>></span><span class="hljs-tag"></<span class="hljs-name">file-upload</span>></span></pre></div><p id="fe67">This property is then passed directly to the <code>accept</code> property of the file input in the file upload template, forcing the user to select a png file from the file upload dialog.</p><h1 id="a737">How to Upload Multiple Files</h1><p id="d62f">By default, the browser file selection dialog will allow the user to select only one file for upload.</p><p id="cb3a">But using the <code>multiple</code> property, we can allow the user to select multiple files instead:</p><div id="af5a"><pre><<span class="hljs-built_in">input</span> <span class="hljs-built_in">type</span>=<span class="hljs-string">"file"</span> <span class="hljs-keyword">class</span>=<span class="hljs-string">"file-upload"</span> multiple></pre></div><p id="a900">Notice that this would need a completely different UI than the one that we have built. A styled upload button with a progress indicator only works well for the upload of a single file.</p><p id="14d6">For a multi-file upload scenario, there are a variety of UIs that could be built: a floating dialog with the upload progress of all files, etc.</p><h1 id="f2f4">Summary</h1><p id="a227">The best way to handle file upload in Angular is to build one or more custom components, depending on the supported upload scenarios.</p><p id="b3e1">A file upload component needs to contain internally an HTML input of type file, that allows the user to select one or more files from the file system.</p><p id="e4ad">This file input should be hidden from the user as it’s not styleable and replaced by a more user-friendly UI.</p><p id="289e">Using the file input in the background, we can get a reference to the file via the <code>change</code> event, which we can then use to build an HTTP request and send the file to the backend.</p><p id="245e">Also, if you have some questions or comments please let me know in the comments below and I will get back to you.</p></article></body>

The Simplest But Highest-Yielding Skill I Wish I Knew 3 Years Ago (that would have got me what I wanted faster)

Here’s my spin on it

Photo by SIMON LEE on Unsplash

No one wants to be told ‘you suck’.

No one wants to be told ‘this isn’t how you do it’.

We’re fragile creatures and we have it hardwired to want to avoid hard things that could be seen as a threat.

I was one of those people who struggled to take negative feedback.

But now it’s something that I wish everyone would seek out as it can be the unlock for you, your pursuits and those you love.

Codie Sanchez — investor and CEO — spoke about the need for people who will tell you when something is s*it. They’ll give you negative feedback.

You want them in your life, and you want to seek them out. Good feedback will supercharge progress, it will highlight areas you might have missed, take a look at the issue in a different way and use the knowledge of the feedback giver.

The thing about feedback is you don’t always have to use it, just hear it out, process it and see if it unearths anything.

The biggest unlock that gave me tangible proof to how you handle and process feedback, meant the difference between an average and an outstanding outcome.

There was one time at university where I had a two part assignment. You’d write the first half, hand it in, get it graded, then complete the second half.

To my annoyance the first half came back 2 marks shy of a fail grade , I was pretty annoyed.

The feedback read ‘this is a poor attempt’, amongst a few other points.

Now it was either the feedback i recieved OR it was because I wasn’t fond of this lecturer (either one I’m not entirely sure of to this day) that lit something up in me.

It was a ‘I’ll show you’ type of energy. I took every single point of the feedback on-board, and got to work on the second half.

After the same process I had it given back to me with the highest mark I’d ever had.

Although that sounded like a s*itty LinkedIn post, it was a pretty huge moment for me.

I wanted to see if it actually worked outside of school, so during my work as a video editor, I am constantly asking for feedback from anyone and everyone.

99% of the time I learn something from it and can make what I produce better because of it.

You can’t grow if you are just hearing what you want to hear all of the time.

Let people rip something apart for you.

Smash your idea up, repair it with feedback and make it look even cooler than it once did . ‘Kintsugi’ I learnt recently is the art of repairing pottery with gold accents and looks a whole lot cooler.

Kintsugi your projects with feedback.

Photo by SIMON LEE on Unsplash

Look for people who will tell you something isn’t your best work.

I will preface this with the feedback needs to be constructive, not malicious. Some people want to always point out flaws and negativity as it feeds them.

Know how to tell the difference.

The type of person who will push you to do more constructively and will not sugar-coat things all the time are few and far between.

They can come in many forms, but you primarily want someone to challenge you, not just blindly agree.

Chris Williamson and Codie Sanchez speak about how ‘Yes men’ can create the death of a business — although I’m not a business owner, I can understand why.

How are you going to know if you are making a huge error if the people around you are just saying ‘yes’ all of the time?

A good rule of thumb to know what feedback to take on and what to throw away is

Knowing YOUR own limits, not what someone else projects onto you.

Read that one again.

If someone is pointing out to you that you’re working all the time and it’s not healthy, that’s fine, you have a choice now.

You should analyse that feedback and determine the following:

  • What are my limits with this, have I got a poor result in the past becasue I worked too hard and vice versa?
  • Is this someone who I respect their opinion enough to take on board? Do I want what they have in this arena?
  • Can I get them to delve deeper into this, could I find something valuable as to why they’ve said it?

How to apply to your life

  • Demand feedback — it’s a slingshot to growth in any field.
  • Hear the feedback, analyse it and determine if it’s worth taking on board, or ignoring.
  • Just hearing the feedback can be a catalyst for change.
  • Do not be surrounded by yes men, find people who can tell you like it is.
Creativity
Personal Development
Life Lessons
Self Improvement
Freelancing
Recommended from ReadMedium