Posts Tagged ‘javascript’

The dark side of the force

I have been spending a lot of time lately working on a new javascript based interface. As with any js project we ended up with a lot of layers. For instance for a simple numeric input there are:

The fun part is that we needed of course some functionality which did not existed in the kendo component (adding support for financial shortcuts: 10k => 10,000).

Since I still have an OOP structured mind, with lot of years of java pattern I thought: Ok, will create a component which extends on kendo and re-wrap.

This would look similar to:

$(function() {
 
    // wrap the widget in a closure. Not necessary in doc ready, but a good practice
    (function($) {
 
        // shorten references to variables. this is better for uglification 
        var kendo = window.kendo,
            ui = kendo.ui,
            NumericTextBox = ui.NumericTextBox;
 
        // create a new widget which extends the first custom widget
        var NumberInput = NumericTextBox.extend({
 
            // every widget has an init function
            init: function(element, options) {
                var that = this;
                NumericTextBox.fn.init.call(that, element, options);
 
            },
 
            _keypress: function(e) {
                //override here!!
            },
 
            options: {
                name: "NumberInput"
            }
        });
 
        // add this new widget to the UI namespace.
        ui.plugin(NumberInput);
 
    })(jQuery);
});

Well, this seemed ok and it worked ok but still requires a lot of work to wrap into an usable aurelia component which maps all the events and options: precision, step …

At this moment it struck me! This is javascript! BUHUHU, there is no need for all this. I could just do this in our wrapper:

    attached() {
        this.taskQueue.queueTask(() => {
            //assuming ak-numerictextbox="k-widget.bind:numericTextBox; in the template
            this.numericTextBox._orig_keypress = this.numericTextBox._keypress;
            this.numericTextBox._keypress = this._keypress;
        });
    }

Now I have switched to the dark side of the force! More details on this github.
 

 

A few thoughts about http fetch

Fetch is the “de facto” standard now if building a new javascript code. Even if not yet supported by all browsers it is warmly recommended. There are numerous examples of usage but after reading a lot of them most of them seemed to miss the answer to my questions. These where:

  • how to proper do error handling including having a default error handler which can be overriden
  • how to do http POST?
  • how to use in real-life application? I mean one would expect to do a fetch for a login api and then all other api to work (i.e. have cookie support).

The following code (typescript) will try to answer the above questions:

function myFetch(path: string, params: Object, customCatch: boolean = false): Promise {
    let requestParams: RequestInit = {
        mode: 'cors',
        cache: 'default',
        credentials: 'include' //this is REQUIRED to enable cookie management
    };
 
    requestParams.body = $.params(object); //generate a query string: 'param1=val&param2=val';
    requestParams.headers = {
        "Content-type": "application/x-www-form-urlencoded; charset=UTF-8" //this is REQUIRED for POST with this payload
    };
    requestParams.method = 'POST';
 
    return fetch(path, requestParams)
        .then(response => {
            if (response.ok) {
                return response.text();
            } else {
                throw (response);
            }
        })
        .catch(err => {
            //please note that "TYPEERROR: FAILED TO FETCH" is a very BAD error message. From the spec:
            //"A fetch() promise will reject with a TypeError when a network error is encountered, 
            //although this usually means permission issues or similar"
            if (customCatch) {
                //this allows to override error handler with a custom function
                throw (err);
            } else {
                if (err instanceof Response) { //server error code, thrown from else above
                    //handle this error
                } else { //this is network error
                    //handle this error
                }
            }
            return null;
        });
}
 
//fetch with default error handling
myFetch('/api', {user: 'toto', task: 'info'})
    .then(
        response => {
            if(response != null){
                //handle response
            }
        });
 
//fetch with custom error handling
myFetch('/api', {user: 'toto', task: 'info'}, true)
    .then(
        response => {
            if(response != null){
                //handle response
            }
        })
    .catch(errResponse => {
        //handler errResponse (both error status and network error)
    })

 

 

Dynamic Aurelia

From someone used to developing in a “traditional” way, switching to a javascript framework is like crossing over to a different universe where the laws of physics do not really apply. They might seem similar but they’re not. Take inheritance for instance, the foundation stone of OOP and throw it down the drain. No more inheritance, everything is composition right now.

Yet in time you will learn the new laws and adapt. Making the decision on which framework to choose has been one of the toughest things I had to do, but finally I am content with choosing Aurelia. It’s structured and comprehensible.

One of the things less documented, however, is the way to do dynamic composition programmatically (in code), as opposed to declarative (in html). This means adding a new element in the DOM and loading a component into it or loading directly some html string with Aurelia markup.

I currently found 3 ways of doing this, and even if I don’t know which is the recommended, one I will mention all of them below. I want to thank all the articles and gitter help I got in making the code below work.

Using the compositionEngine.compose()

The compose element is the way Aurelia allows you to insert a dynamic component into the page. What if there is no compose markup and you want to add a variable number of components?
This corresponds to the following use case scenario: I have a menu navigation which opens tabs for each different application module. Each module is implemented as a component (they do not inherit a base class!). When the user opens a menu entry, a new tab is created and the corresponding component loaded. A working example can be found in this gist.

To add a new tab, a new DOM node is created using basic javascript, then the CompositionEngine.compose is called provided with a viewModel, the component name, and a slot to attach to, the newly created element.

this.instruction = Object.assign(this.instruction, {viewModel: menuId, host: el, viewSlot: vSlot});
this.compositionEngine.compose(this.instruction).then(controller => {
       vSlot.bind();
       vSlot.attached();
});

Please note that the limitation I currently found to this method is that if 2 instances of the same component are created they will share the same instance of the viewModel. Test here by opening “second module” twice and changing the value. This is due to the fact that the viewModel is obtained using container.get() which by default returns a singleton. One solution is the mark the viewModel with transient(), another would be to create the viewModel instance and add it to the child container (I guess this is Aurelia does internally for the components). Also don’t forget to call unbind and detach on the component if you also plan to allow for the components to be removed.

Using enhance

A simpler method is to insert the markup for the compose element directly and call templatingEngine.enhance on it. This also does not suffer from previous viewModel reusage limitation.

...
              content: '<compose view-model="' + menuId + '" id="' + moduleDivId + '"></compose>',
              encoded: false
          });
 
      let el = document.getElementById(moduleDivId);
      let view = this.templatingEngine.enhance({ element: el, bindingContext: {}, overrideContext: {}});

See more info here.

Please note that I think the api has changed recently since I am experiencing some trouble with this method on latest aurelia-templating.

Using the viewCompiler

Both previous methods add a component dynamically in html in a place where no previous markup exists. At some point however one might wish to load a chunk of html containing aurelia markup in the current DOM. Take the usecase where parts of a form are user generated and are loaded from the server at runtime. Check the gist here. As you see, when the html is loaded, binding also takes place.

The dynamic part happens here:

        let viewFactory = this.viewCompiler.compile(html, this.resources);
        let view = viewFactory.create(this.container);
        view.bind(viewModel, createOverrideContext(viewModel));
        let viewSlot = new ViewSlot(containerElement, true);
        viewSlot.add(view);
        viewSlot.attached();
        return () => {
            viewSlot.remove(view);
            view.unbind();
        };

 

Update NumericTextBox precision on the fly

As currency selection changed you naturally want to change the precision and format of a NumericTextBox which contains an amount in the given currency (damn JPY for not using the same precision as everyone else).

At a first glance one might think this can be accomplished using computed properties and something like:

    @bindable precision:number = 2;
 
    @computedFrom('precision')
    get step():number {
        return Math.pow(10, - this.precision);
    }
 
    @computedFrom('precision')
    get format():string {
        return "n" + this.precision;
    }
<input type="number" ak-numerictextbox="k-value.two-way:value; k-spinners.one-way:spinners; k-format.one-way:format; k-decimals.one-way:precision; k-step.one-way:step"/>

However this is not possible and in this specific case there are no kendo functions to achieve this.

The only option, short of recreating the control each time the currency changes is to use the setOptions method as described here:

    precisionChanged(newValue, oldValue){
        let step = Math.pow(10, - this.precision);
        this.numericTextBox.setOptions({format: 'n' + newValue, decimals: newValue, step: step});
        this.numericTextBox.value(this.value);
    }

Please note the value(value()) is a very ugly hack. See running gist.

 

Dispatch change events in custom components

This is the first post about Aurelia and the Kendo-UI-Bridge. It’s a brave new world for me.

The goal was to create a custom component (which wraps a ak-combobox) and dispatch a change event in a similar way to the standard components (i.e ak-combobox, ak-datepicker, etc.).

<input ak-datepicker="k-value.two-way: model.date" k-on-change.delegate="onChange($event)"/>

For these components, the change event is dispatched after the model changes.

In my component code I had initially wrapped the k-on-change from the base component and continued dispatching it.
This however did not had the desired effect. The wrapping component emitted the event before the model was updated (binding was updated).

<dictionary-combo value.two-way="model.currency" k-on-change.delegate="onChange($event)"></dictionary-combo>
    onChange(event){
       event.stopPropagation();
       this.dispatch()
    }
 
    dispatch(){
      this.dispatchCustomEvent(this.element, "k-on-change", {value: this.value});
    }
 
    dispatchCustomEvent(element:Element, type:string, detail:Object, bubbles:boolean){
        let newEvent;
        if (window.CustomEvent) {
            newEvent = new CustomEvent(type, {
                detail: detail,
                bubbles: true
            });
        } else {
            newEvent = document.createEvent('CustomEvent');
            newEvent.initCustomEvent(type, bubbles, true, {
                detail: detail
            });
        }
        element.dispatchEvent(newEvent);
    }

The solution is to delay the event. Stop propagating the initial event and add the action of sending the new event to the aurelia taskQueue. This would ensure the event occurs after the binding and can be done:

    onChange(event){
       event.stopPropagation();
       console.log("dictionaryCombo.onChange: " + this.value);
       //wrong way: this.dispatch()
       this.taskQueue.queueMicroTask(() => this.dispatch());
    }

Refer to this gist for complete example.

Please note that I found this, thanks to the wonderful guys on the aurelia-kendo-ui gitter to which I remain grateful
 

Frame sketcher, the model

If someone had asked me some time ago about bicycle frame geometry I would have answer simply in terms of 19”, 20” for MTB or 56, 58 for a road bike. I was of course aware of basic measurements such as Top Tube length or Standover Height and have passed a few times my measurements through a fit calculator but I haven’t given much thought from a geometric, or trigonometric to be more precise, point of view.

However comparing bicycle frames online I realized there are a lot of subtle changes which ultimately affect your riding style and comfort which are not contained in an information such as: “This is an 18” frame”. For this reason I started digging through my math old knowledge and wrote a small app to sketch and compare bicycle frames.

(more…)

Frame sketcher, introduction

I am searching for a new bicycle. Partly as a gift to one self, partly to make sure if the current one fails I will not be under pressure to buy one fast. As such I have done a lot of research into the subject.

One of the elements I have found is that I could achieve a better price/quality ration buying online especially from German based online shops.

This poses a big problem on testing since frame geometry differs a lot from manufacturer to manufacturer. In order to solve this problem, at least by some measure, I created a tool which allows to simply sketch and compare several frames using manufacturer frame geometry data. (more…)

Enhancing a web application with jquery

I’ve decided to use jquery for the first time in order to implement in the simplest possible way the following problem

The problem

I wanted to use an existing search/navigation mechanism to select the value of a new input field by making as little modifications as possible to the existing code. Since searching for the item implied navigating a few pages passing information along all the submits or links was impossible without extensive changes.

The idea

My idea was to use a popup to search/navigate in search of the item (nothing new until here) but in the popup to store the information required for the return in a top, invisible frame and to use jquery to detect this state and enhance the final selection window with new elements. The modifications to the initial code would imply just setting the name of a div to the id of the item.

The opener

Here is a simplification of the page containing the input to be filled:

...
    <script type="text/javascript" src="jquery-1.3.2.min.js"></script>
    <script type="text/javascript">
function openProductSelectWindow(fieldId){
        aWindow = window.open('frame.html?target=single.html&fieldId=' + fieldId, 'productSelect', 'scrollbars,height=700,width=700', false);
        aWindow.focus();
}
    </script>
</head>
<body>
<form>
<input type="text" id="myField"/><a href="javascript:void(0);" onclick="openProductSelectWindow('myField');">select</a>
</form>
</body>

There is nothing special here, except that I wanted to use a more general approach and I pass as a parameter the page used for navigation.

The frame

Here is a simplification of the frame page:

  <script type="text/javascript" src="jquery-1.3.2.min.js"></script>
  <script type="text/javascript" src="jquery.query-2.1.2.js"></script>
  <script type="text/javascript">
$(document).ready(function(){
 	var targetPage = $.query.get('target');
	$('#mainframe').attr({'src': targetPage, 'name': 'product'});
});

function topAction(pId){
	window.opener.$('#'+$.query.get('fieldId')).attr('value', pId);
	window.close();
}
  </script>
</head>
<frameset rows="100%">
<frame id="mainframe"/>
</frameset>

I am using the query parsing plugin for jquery and some attributes related functions.

The application page

<script type="text/javascript">
 $(document).ready(function(){
   if(window.top != window){
   	$("#myP").css({'display':'none'});
	$("#productsTable tr td").filter(".lastColumn").css({'display':'inline'});
   }
 });

function productSelect(pId){
	if(window.top != window){
		$("#product" + pId).append('<a href="javascript:void(0);" onClick="window.top.topAction(\'' + pId + '\');">select product</a>');
	}
}
</script>
<style type="text/css">
.lastColumn {display:none;}
</style>
...

<table id="productsTable">
<tbody>
<tr id="productsTableHeader">
<td class="tableHead">Key</td>
...
<td class="lastColumn">Select</td>
</tr>
<tr>
...
<td id="product80111" class="lastColumn">
<script type="text/javascript">productSelect('80111');</script>
</td>
</tr>

The only modification required to the application page was to add a new column, modify the style file and add the extra javascript which detects it the page is opened inside a frame or not and in the first case changes the style of the otherwise hidden column. There is no risk if this column is shown otherwise because it’s content is also generated using jquery using the same type of condition.