poniedziałek, 15 maja 2017

Angular 2 - Declarative forms

Angular comes with a little bit bloated way of creating forms. Creating each field manually definitely give us full control of how particular fields will look, but on the other hand if there are more then couple fields it is terribly tedious. Moreover, any change requires visiting all places given ux pattern is used (eg. displaying validation errors, labels, etc.)). The declarative way of defining such forms seems to be ideal solution.. but there is no such out of the box.. It's sad.

Luckily Angular with its expressiveness allows us develop a solution. Let's create component that takes array of controls and build the form.

@Component({
  selector: 'app-root',
  template: `<div style="margin: 50px">
 <declarative-form [controls]="controls" (submitMe)="onSubmit($event)"></declarative-form>
</div>`
})
export class AppComponent {

  controls: Object[] = [
    {name: 'name', label: 'Yout name', type: 'text'},
    {name: 'name2nd', label: 'Your second name', type: 'text'},
    new Control('name3rd', 'Your third name'),
    {name : 'description', label: 'Descrition', type: 'textarea' },
    new Control('age', 'Your age', 'range'),
    new Control('mobile', 'Mobile number'),
    new Control('gender', 'Gender', 'radio', {'options' : ['Male', 'Female']}),
    new Control('favFood', 'Favourite Food', 'radio', {'options' : ['Pasta', 'Pizza', 'Hamburgers', 'Soups', 'Chinese']}),
    new Control('country', 'Country', 'dropdown', {'options': ['US','PL', 'DE']}),
  ]

  onSubmit(values) {
    console.log(values);
  }   
}
Ok, let's start with creating declarative-form component
@Component ({
    selector: 'declarative-form',
    template: `<form [formGroup]="form" novalidate>
      <my-form-input *ngFor="let control of controls"
        name="{{control.name}}" 
        label="{{control.label}}" 
        type="{{control.type}}"
        [params]="control.params"
        [form]="form"></my-form-input>
        <button type="submit" (click)="onSubmit()">Submit me</button>
</form>
<pre>{{form.value | json}}</pre>`
})
export class DeclarativeFormComponent{

  @Input()
  controls: Control[];

  @Output()
  submitMe = new EventEmitter();

  form: FormGroup;

  constructor(private formBuilder: FormBuilder) {
  }

  ngOnInit(){
    let cfg = new Object();
    this.controls.forEach(c => cfg[c.name] = '');
    this.form = this.formBuilder.group(cfg);
  }

  onSubmit(){
    console.log(this.form.value);
    this.submitMe.emit(this.form.value);
  }

}
The ngOnInit function is most tricky here. What it does is creating configuration object for the form builder. The last missing piece is my-form-input component - your homework ;)

czwartek, 20 kwietnia 2017

Angular2 - Cannot read property 'id' of undefined for ngModel

Lets take the following piece of code
 <form>
    <select [(ngModel)]="project.id"...
In this case when there is no 'project' value set yet it will be thrown an error with the following message: Cannot read property 'id' of undefined

Maybe '?' operator can help us? Let's try.

 <form>
    <select [(ngModel)]="project?.id"...
Nope, this will cause template parsing error: Parser Error: The '?.' operator cannot be used in the assignment at column 13 in [project?.id=$event]

And what about the ngIf directive?

 <form *ngIf="project" >
    <select [(ngModel)]="project.id"...
Ufff. It works ;)

wtorek, 4 kwietnia 2017

Angular2 - Two ways of injecting dependencies

There are two ways of delivering dependencies to the created object. One is the widely know "injection by type", which is done by specifying typed parameters in constructor.

Inject by Type

constructor(private service: MyService) {
}
This assumes MyService is imported specific class put into providers of your module.

Inject by Name

Another way is "injecting by name".

constructor(@Inject('myService') private service) {
}
This time we required the following in the module providers list
{provide: 'myService', useClass: MyService},
The main advantage of the latter is we actually get rid of importing specific class, though, decouple from other local resources

We can also provide values instead of classes:

{provide: 'url', useValue: 'http://localhost'},

wtorek, 28 marca 2017

Angular2 - How to read params out of the current url

Lets say we want to take `id` param out of the current url. To do so we need to obtain current route by injecting "ActivatedRoute" object and read its params.
    constructor(private _route: ActivatedRoute){
        this.id = _route.params.map(param => param.id);
    }
The `id` field will be of Observable type.

poniedziałek, 14 listopada 2016

Java - stop reading possibly huge xml once given element found

  Path versionFile = installationPath.resolve("large.xml");

  SAXParserFactory factory = SAXParserFactory.newInstance();
  SAXParser parser = factory.newSAXParser();

  InputStream is = openStream(versionFile);

  class BreakException extends SAXException {
   private String value = null;
   private static final long serialVersionUID = 1L;
  }

  try {
   parser.parse(is, new DefaultHandler() {
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
     if ("InstallType".equals(qName)) {
      String value = attributes.getValue("currentVersion");
      // really dirty way to break sax parsing on demand and return value out of anonymous handle by the way ;)
      BreakException breakException = new BreakException();
      breakException.value = value;
      throw breakException;
     }
    }
   });
  } catch (BreakException be) {
   return be.value;
  }

wtorek, 5 kwietnia 2016

git - stucked with modified files due to eol differences

Once you've got * text=auto set in your .gitattribute file all text files stored in repository will be changed into EOL sequence adequate to the host system. But any time checkouting on another system - all eols will be replaced with its specific. Quite nifty, isn't it?

But if for some reason your text file you've got in staging area contains for instance CRLF and you are working on linux machine - git status reporting it as modified. But you cannot reset this as there are no diff in terms of text=auto. Moreover git stash also seems to work badly, as again nothing to stash found. If you faced such a problem here is the solution

  1. Edit the .gitattribute file by commenting out the * text=auto line (with # sign)
  2. Type git status on the command line
  3. Revert .gitattribute file

czwartek, 14 stycznia 2016

Ubuntu - disappeared unity windows recovery guide

I found myself really confused that after some operations (eg. switching external displays around) I cannot activate opened applications. I suspected that those apps have to be somewhere on desktop, but apparently not in current view port. There have to be a way to grab and move them.. but how??

After a while of googling wmctrl nifty friend was on my toolbox ready for action.

Lets start from looking at options by typing wmctrl -h for displaying a help.
Now try to figure out what windows are on your desktop:

$ wmctrl -l
0x02e00002  0 krma-laptok XdndCollectionWindowImp
0x02e00005  0 krma-laptok unity-launcher
0x02e00008  0 krma-laptok unity-panel
0x02e0000b  0 krma-laptok unity-dash
0x02e0000c  0 krma-laptok Hud
0x0280000a  0 krma-laptok Desktop
0x0460000b  0 krma-laptok krma@krma-laptok: ~
0x044000b3  0 krma-laptok Inbox - Mozilla Thunderbird
0x0400053b  0 krma-laptok Java - Eclipse 

Lets look at the desktop present on our system
$ wmctrl -d
0  * DG: 3840x1080  VP: 0,0  WA: 45,24 3795x1056  N/A
But how to identify those that are out of viewport?
$ wmctrl -lG
0x02e00002  0 -3940 -1180 3840 1080 krma-laptok XdndCollectionWindowImp
0x02e00005  0 0    24   45   1056 krma-laptok unity-launcher
0x02e00008  0 0    0    1920 24   krma-laptok unity-panel
0x02e0000b  0 -1241 -740 1141 640  krma-laptok unity-dash
0x02e0000c  0 -1060 -164 960  64   krma-laptok Hud
0x0280000a  0 0    0    3840 1080 krma-laptok Desktop
0x0460000b  0 2101 114  1601 844  krma-laptok krma@krma-laptok: ~
0x044000b3  0 70   266  1294 629  krma-laptok Inbox - Mozilla Thunderbird
0x0400053b  0 7655 92   1860 988  krma-laptok Java - Eclipse
Eclipse's x position seems to be a little to high, isn't? Lets move it to (20,20) and leave existing size (1860,988) unchanged:
$ wmctrl -i -r 0x0400053b -e 0,20,20,-1,-1
PS. another nice tool is xdotool. It can
$ xdotool getwindowgeometry 0x0400053b
Window 67110203
  Position: 55,62 (screen: 0)
  Geometry: 1860x988
Note that position is different from (20,20) - moved (35,42)??