Framework: href.bind check for undefined and null

Created on 4 Jan 2016  路  8Comments  路  Source: aurelia/framework

href.bind should check for undefined and null properties and not create a href element if that is the case.

The use case is optional link anchor's, current the code is necessary to create the behaviour:

     <a if.bind="href != undefined || href != null" href.bind="link" click.trigger="toogle()">
        <i if.bind="icon != null" class="uk-icon-${icon} uk-icon-small"></i> ${title}
        <div if.bind="badge != null" class="uk-badge uk-badge-${badgeStatus}">${badge}</div>
      </a>
      <!-- Duplication for no href -->
      <a if.bind="href == undefined || href == null" click.trigger="toogle()">
        <i if.bind="icon != null" class="uk-icon-${icon} uk-icon-small"></i> ${title}
        <div if.bind="badge != null" class="uk-badge uk-badge-${badgeStatus}">${badge}</div>
      </a>

if href.bind check for null and undefined properties the duplication above is unnecessary

All 8 comments

I think that every bind of a property should check for null and undefined and not create the property in the dom

If you don't have an href on the Anchor it will not appear to be clickable so I think it should be left as-is personally. No reason to remove the attribute from the DOM since it isn't like readonly or disabled where the attribute being there actually does something unless I am missing something.

That is exactly the behavior expected for a link with no href, it is not clickable. Or to be more a curate it prevents the default click and do not perform a undesired navigation to null. And is useful in many situations

If you do not forget layout and styling, it is the best non boilerplate way to create menus.
Another reason is that any tag=null tag=undefined should have side effects unless null and undefined are what the developer want, in this case it should be a string

ES2106:

import {SyntaxInterpreter} from 'aurelia-templating-binding';
import {ObserverLocator} from 'aurelia-binding';

var propertyAccessor = {
    getValue: (obj, propertyName) => obj[propertyName],
    setValue: (value, obj, propertyName) => {
        if ((value == null) || (value == undefined)) {
            obj.removeAttribute(propertyName);
            return value;
        }

        return obj[propertyName] = value;
    }
};

class TestObserverLocator extends ObserverLocator {
    getAccessor(obj, propertyName) {
        return propertyAccessor;
    }
}

SyntaxInterpreter.prototype['testbind'] = function bind(resources, element, info, existingInstruction, context) {
    var instruction = this.bind(resources, element, info, existingInstruction, context);

    var bindingExpression = instruction.attributes[info.attrName];
    var observerLocator = bindingExpression.observerLocator;
    bindingExpression.observerLocator = new TestObserverLocator(observerLocator.taskQueue, observerLocator.eventManager, observerLocator.dirtyChecker, observerLocator.svgAnalyzer, observerLocator.parser);

    return instruction;
};

then use like this:

<a href.testbind="some property">test</a>

i don't know if it is recommended, but it can work.
and this logic can not impl by typescript, because the d.ts export ObserverLocator as a interface
so use typescript, i only find the way can work(i like the ES2016 logic more):

import {SyntaxInterpreter} from 'aurelia-templating-binding';

// 'this' is binding
function updateTarget(value) {
    if ((value == null) || (value == undefined)) {
        this.target.removeAttribute(this.targetProperty);
        return value;
    }

    return this.target[this.targetProperty] = value;
};

SyntaxInterpreter.prototype['testbind'] = function bind(resources, element, info, existingInstruction, context) {
    var instruction = this.bind(resources, element, info, existingInstruction, context);

    var bindingExpression = instruction.attributes[info.attrName];
    var createBinding = bindingExpression.createBinding;
    bindingExpression.createBinding = function(target) {
        var binding = createBinding.call(bindingExpression, target);
        binding.updateTarget = updateTarget;
        return binding;
    }

    return instruction;
};

anyone can tell me, what's the recommended way to do "href.bind check for undefined and null"
and my project is based on typescript.

Closing for now. We aren't planning to change this, but as shown above, it's possible to extend the binding system in such a way as to customize this behavior.

this is more of a hack to workaround the problem than a solution. I agree with @giovannicandido that removing the attribute would be best. also, many css libraries and frameworks add or remove styling depending on whether an anchor has an href attribute, so <a href="undefined"></a> will be styled as <a href="#/some/valid/route"></a> and that's generally not desired

There is a pending PR to address this at aurelia/binding#616

Was this page helpful?
0 / 5 - 0 ratings