Friday, June 23, 2017

Fire and forget with Angular 2 REST service calls.

Consider this:

this.http.put(myUrl, myJson, myOptions);

 
 

It does nothing. It fails silently. You have to chain stuff off of the put to get it to do something like so:

this.http.put(myUrl, myJson, myOptions).toPromise().then(function(){},
      function(){}).catch(function(){});

 
 

That's terrible too because, per Roy Fielding, PUT as a verb should not roundtrip something back up to you. At your ASP.NET Web API endpoint you should just have a void method and not a method that returns a true value bool as a hack to accomodate Angular 2. The fix is this:

this.http.put(myUrl, myJson, myOptions).toPromise();

 
 

This was allow you to hit an endpoint that returns void.

Thursday, June 22, 2017

when newing up a specific date in JavaScript/TypeScript...

var whatever = new Date(1974, 7, 24);

This date is going be August 24th of 1974 and not July 24th of 1974. Remember the goofy zero to eleven scale for month. You have to think of it when it comes to pulling the month back out. Bonus: Also note that .getUTCFullYear(), .getUTCDate(), and .getUTCMonth() are a thing when pulling stuff back out.

Wednesday, June 21, 2017

Ctrl-Shift-Z is the Ctrl-Y in WebStorm

You redo an undo (Ctrl-Z) with Ctrl-Shift-Z while Ctrl-Y just seems to destroy the line you are on which is infuriating.

HttpResponseMessage to an MVC Controller causes: Incorrect Content-Type: application/json; charset=utf-8

This error ended up having more to do with the listening ear than what was talking in. The DTO below ended up with a bunch of null values.

[HttpPost]
[Produces("application/json")]
[Route("foo/bar/baz/")]
public string Whatever(MyDto myDto)
{

 
 

This change made the problem go away:

[HttpPost]
[Produces("application/json")]
[Route("foo/bar/baz/")]
public string Whatever([FromBody] MyDto myDto)
{

Tuesday, June 20, 2017

Upload something from Angular 2 with the both the file input type HTML control and Observable.

If this is at your component's template...

<input type="file" (change)="uploadFile($event)">

 
 

...you may kick off this in the component itself:

uploadFile(event:any):void{
   let filePath = event.target.value;
   if (filePath){
      this.myService.uploadFile(event.target.files[0]);
   }
}

 
 

That in turn may reach into your service for this method. Note that Headers and RequestOptions must be imported from '@angular/http' while FormData just seems to magically work.

public uploadFile(file: any): void {
   var url = "http://www.example.com/api/whatever/";
   let formData:FormData = new FormData();
   formData.append('uploadFile', file, file.name);
   let headers = new Headers();
   headers.append('Content-Type', 'multipart/form-data');
   headers.append('Accept', 'application/json');
   let options = new RequestOptions({ headers: headers });
   this.http.post(url, formData, options)
      .catch(error => Observable.throw(error))
      .subscribe(
         data => console.log('success'),
         error => console.log(error)
   )
}

 
 

At the ASP.NET Web API side of things you could have an endpoint like so in a .NET Core Microsoft.AspNetCore.Mvc.Controller:

[HttpPost]
[Route("api/whatever")]
public void SaveStuff()
{
   HttpRequest request = this.Request;
   IFormFile file = request.Form.Files[0];
   using (var reader = new StreamReader(file.OpenReadStream()))
   {
      var fileContent = default(byte[]);
      using (var memoryStream = new MemoryStream())
      {
         var buffer = new byte[file.Length];
         var bytesRead = default(int);
         while ((bytesRead = reader.BaseStream.Read(buffer, 0, buffer.Length)) > 0)
         {
            memoryStream.Write(buffer, 0, bytesRead);
         }
         fileContent = memoryStream.ToArray();
      }
      using (var writer = new BinaryWriter(System.IO.File.Open("C:\\x.jpg",
            FileMode.OpenOrCreate)))
      {
         writer.Write(fileContent);
      }
   }
}

 
 

Clearly the BinaryWriter stuff above is silly. It's just there to show off that the code above works. If you want the file name for the file, you could have gotten above with:

string fileName = file.FileName;

Monday, June 19, 2017

Do not expect to error catch a 404 coming back off an Observable promise.

this.http.get("http://www.example.com/api/whatever").toPromise().then(

...is not going to play nicely with example.com not existing outright. To avoid a blow up you will want to wrap this line of code in a try/catch. How realistic is it to worry about your endpoint not being there? Well, you're still reading, aren't you?

Sunday, June 18, 2017

yet more gunk from a series of Angular 4 training videos

  1. [ngStyle]="{backgroundColor: whatever===13 ? 'red' : 'blue'}" is an example of a condition in an ngStyle.
  2. In making an attribute directive such as myHighlight here you may add something like so at the constructor... private rendery: Renderer2 and then turn around and use it like this:
    ngOnInit() {
       this.rendery.setStyle(this.el.nativeElement, 'width', '50px');
    }

    ...this sort of assumes that private el: ElementRef is also at the constructor.
  3. @HostListener('mouseenter') myMouseEvent(eventData: Event) { is a way to catch a mouseenter event at a tag within your attribute directive. mouseleave and other events are available too.
  4. @HostBinding('style.marginTop') myMargin: string; inside an attribute directive allows for something like this inside a @HostListener method: this.myMargin='10px';
  5. @Input myOffset: string = '10px'; at an attribute directive allows for this.myMargin=this.myOffset; and kinda takes place at the tag itself like so:
    <p myHighlight myOffset="30px;">Highlight me!</p>.
    You may have an alias at the Input to make it whatever you'd like at the tag and you may even make the alias the same name as the selector for the directive! When you do that, you may have something like so:
    <p myHighlight="30px;">Highlight me!</p>
  6. The training kinda touched on making your own structural directive though I don't really see a bunch of reasons to do so myself. If you have something like private foo: TemplateRef<any>, private bar: ViewContainerRef in the constructor then this.bar.EmbeddedView(this.foo); in the getter of a getsetter for an @Input which shares the name with your directive (It has to!) it will allow you to show what is inside of your tag while this.bar.clear(); shows nothing. Based on the value handed in you may write your own thing like *ngIf, but again... why?
  7. The training had an example of doing so some static state stuff in a service and cautioned that if you share a service across two components that, if you want to share state and not have two separate instances, that you need to loop in the provider not at each component but hierarchically above at a component wrapping the components.

Yay! It's fun to build stuff: