# Aurelia alternative for allBindingsAccessor() method on custom bindings

**URL:** <https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910>\
**Category:** Help Requests\
**Created:** [November 16, 2018, 11:26pm UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910 "2018-11-16T23:26:18Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![gooeyideas](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/gooeyideas/32/64_2.png) [@gooeyideas](https://discourse.aurelia.io/u/gooeyideas)\
**Post date:** [November 16, 2018, 11:26pm UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/1 "2018-11-16T23:26:18Z")

</div>

I am converting a custom knockout binding to a custom Aurelia Attribute. When making a custom knockout binding you can use the allBindingsAccessor() to gain access to an observable bound to other bindings and respond to changes in that binding as well.

I was doing this with a `highlight` binding that looked at the string bound to the text binding and wrapped text that matched a regex expression in a span element that applied styles to the matching text.

I need to do something similar with a custom Aurelia attribute and I am looking for some advice about the best way to do this.

**Given this example:**

```auto
//viewmodel
this.description = "this is example text content";
this.query = "example ";

```

```auto
<!-- view -->
<span textcontent.bind="description" highlight.bind="query"></span>

```

**I would want this to render:**

```auto
<span textcontent.bind="description" highlight.bind="query">
    this is <span class="highlight">example</span> text content 
</span>

```

Am I correct in assuming I would need to inject the `bindingEngine` and use `.observerLocator.getObserver()` or something similar to gain access to the `textcontent` binding that would let me subscribe to changes to `this.description`?

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [November 16, 2018, 11:54pm UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/2 "2018-11-16T23:54:25Z")

</div>

All observers of your view model is defined at ` __observers__ ` property. You can do a `for .. in` to get all of them. If you are concerned about the usage of ` __observers__ ` property, then you can do inject `ObserverLocator` and call private method `getOrCreateObserversLookup(obj)` [https://github.com/aurelia/binding/blob/master/src/observer-locator.js#L73-L75](https://github.com/aurelia/binding/blob/master/src/observer-locator.js#L73-L75)

```js
  getOrCreateObserversLookup(obj) {
    return obj. __observers__ || this.createObserversLookup(obj);
  }

```

The property ` __observers__ ` may change but probably not the method `getOrCreateObserversLookup(obj)`

Edit:  
Re:

> Am I correct in assuming I would need to inject the `bindingEngine` and use `.observerLocator.getObserver()` or something similar to gain access to the `textcontent` binding that would let me subscribe to changes to `this.description` ?

So i see that you want get a hold of `textcontent.bind='description'` binding, you can hook into `created()` lifecycle:

```js
class {
  ...
  created(owningView, view) {
    this.view = view;
    this.textcontentDescriptionBinding = view.bindings.find(b => b.targetProperty === 'textcontent')
  }

}

```

---

<div class="post-metadata">

**Author:** ![gooeyideas](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/gooeyideas/32/64_2.png) [@gooeyideas](https://discourse.aurelia.io/u/gooeyideas)\
**Post date:** [November 19, 2018, 9:40pm UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/3 "2018-11-19T21:40:53Z")

</div>

That looks promising however it just returns the first `textcontent` binding in the view. I only need the `textcontent` binding for the element that also has my custom attribute on it.

Do I really need to parse every binding on the view to find this binding?

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [November 19, 2018, 11:15pm UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/4 "2018-11-19T23:15:28Z")

</div>

I guess you can do

```auto
this.allBindingsNeeded = view.bindings.find(b => b.targetProperty === 'textcontent' && b.target.au && b.target.au.highlight)

```

---

<div class="post-metadata">

**Author:** ![gooeyideas](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/gooeyideas/32/64_2.png) [@gooeyideas](https://discourse.aurelia.io/u/gooeyideas)\
**Post date:** [November 19, 2018, 11:31pm UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/5 "2018-11-19T23:31:03Z")

</div>

Actually, `b.target === this.element && b.targetProperty === 'textContent';` seems to filter just fine but I am struggling to get a subscription to work.

I would think that inside of bind I could:

```javascript
bind(binding, source) {
    if(typeof this.textcontentBinding !== 'undefined') {
      this.textcontentSub = this.textcontentBinding.observerLocator.getObserver(binding, this.textcontentBinding.targetProperty).subscribe((value)=>{
        //do stuff with textcontent value?
      });
    }
}

```

But this is not being triggered when the property bound to the textcontent binding is changed. What am I doing wrong here?

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [November 19, 2018, 11:51pm UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/6 "2018-11-19T23:51:40Z")

</div>

```auto
this.textcontentBinding.observerLocator.getObserver(
  binding,
  this.textcontentBinding.targetProperty
)

```

Doing that means you are observing `targetProperty` of binding object, instead of view model. I’m also uncertain about your bind method, is it in your view model, or in your custom binding class. If it was in view model, change it to:

```auto
bind(bindingContext, overrideContext) {
    if(typeof this.textcontentBinding !== 'undefined') {
      this.textcontentSub = this.textcontentBinding.observerLocator.getObserver(this, this.textcontentBinding.targetProperty).subscribe((value)=>{
        //do stuff with textcontent value?
      });
    }
}

```

But you can see that you can easily do the same thing, from within view model using change handler.

---

<div class="post-metadata">

**Author:** ![gooeyideas](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/gooeyideas/32/64_2.png) [@gooeyideas](https://discourse.aurelia.io/u/gooeyideas)\
**Post date:** [November 20, 2018, 12:48am UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/7 "2018-11-20T00:48:34Z")

</div>

Thanks for your help but this still doesn’t work. All of this code needs to work from inside a separate custom attribute class declaration. Please refer to my original question as for what I am trying to achieve. I effectively need to extend the functionality of the textcontent attribute with my custom highlight attribute. This was easy to achieve in knockout but it seems to be very complicated to pull off with Aurelia.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [November 20, 2018, 12:57am UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/8 "2018-11-20T00:57:58Z")

</div>

> All of this code needs to work from inside a separate custom attribute class declaration

That was not made clear, or I completely missed it.

> This was easy to achieve in knockout but it seems to be very complicated to pull off with Aurelia.

From what you have shown so far, I’m pretty sure it can be done easily as well, but I’d need some pseudo code, or some explanation for this, before I can put together an example `I effectively need to extend the functionality of the textcontent attribute with my custom highlight attribute`

---

<div class="post-metadata">

**Author:** ![gooeyideas](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/gooeyideas/32/64_2.png) [@gooeyideas](https://discourse.aurelia.io/u/gooeyideas)\
**Post date:** [November 20, 2018, 1:11am UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/9 "2018-11-20T01:11:38Z")

</div>

The best way would be to show what knockout allowed:

```javascript
ko.bindingHandlers.highlight = {
    update: function(element, valueAccessor, allBindings) {
        // First get the latest data that we're bound to
        var value = valueAccessor();
 
        // Next, whether or not the supplied model property is observable, get its current value
        var valueUnwrapped = ko.unwrap(value);
 
        // Grab some more data from another binding property
        var text = allBindings.get('text') || "";
        var textUnwrapped = ko.unwrap(text);
        // Now call a function passing in the text query and the source text binding string to highlight and return highlighted html string
        var highlighedtext = regexHighlight(valueUnwrapped, textUnwrapped);

          // update value of element
         element.innerhtml = highlighedtext;
    }
};

```

Is it possible to I recreate this functionality with a custom Attribute using Aurelia?

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [November 20, 2018, 1:27am UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/10 "2018-11-20T01:27:13Z")

</div>

A crude translation, to make it familiar:

```auto
import { Binding, View } from 'aurelia-framework';

@inject(Element)
@customAttribute('highlight')
export class Highlight {

  // This is magic property of all custom attribute,
  // by default if no primary bindable specified
  value: string;
  // reference of bindings we want to deal with
  relevantBindings: Binding;

  constructor(public element: Element) {}

  // owning view is the view of the custom element where this attribute
  // resides in
  created(owningView: View) {
    this.relevantBinding = owningView.bindings.find(b => b.target === this.element && b.targetProperty === 'textContent');
  }

  /**
   * 
   */
  valueChanged(newValue) {
    let binding = this.relevantBinding;
    let textUnwrapped = binding.sourceExpression.evaluate(binding.source, binding.lookupFunctions);
    let highlighedText = regexHighlight(newValue, textUnwrapped);
    this.element.innerHTML = highlightedText;
  }
}

```

A better version of this would be to pass the `description` to the custom attribute, so it can handle the highlighting all by its own, instead of go looking for the binding and evaluate its expression value:

```auto
<span highlight="query.bind: query; text.bind: description"></span>

```

```auto
import { customAttribute, inject, bindable } from 'aurelia-framework';

@inject(Element)
@customAttribute('highlight')
export class Highlight {

    @bindable() query: string;
    @bindable({
      primaryProperty: true
    })
    text: string;

    constructor(public element: Element) {}

    /**
     * implement bind to stop initial change handler invokations
     * (2 of them, because of 2 bindables specified in the view)
     */
    bind() {
      this.propertyChanged();
    }

    propertyChanged() {
      let highlighedText = regexHighlight(this.query, this.text);
      this.element.innerHTML = highlightedText;
    }
}

```

Now whenever `query` or `description` change, you get what you want. Can you try it?

Note that we `primaryProperty: true` for text is to make the public API of the custom attribute more intuitive

---

<div class="post-metadata">

**Author:** ![gooeyideas](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/gooeyideas/32/64_2.png) [@gooeyideas](https://discourse.aurelia.io/u/gooeyideas)\
**Post date:** [November 20, 2018, 1:59am UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/11 "2018-11-20T01:59:44Z")

</div>

In your first example, does calling `evaluate` create a subscription?

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [November 20, 2018, 2:05am UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/12 "2018-11-20T02:05:09Z")

</div>

No, it just does what it says: evaluates the value, based on view model and an expression specified in the view.

---

<div class="post-metadata">

**Author:** ![gooeyideas](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/gooeyideas/32/64_2.png) [@gooeyideas](https://discourse.aurelia.io/u/gooeyideas)\
**Post date:** [November 20, 2018, 2:20am UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/13 "2018-11-20T02:20:22Z")

</div>

Then it does not recreate the custom knockout binding which updates whenever the value of the text binding changes. When you call the `ko.unwrap()` it creates a subscription that will trigger the custom binding’s update method to achieve this.

Please keep in mind that the example I gave was also a “crude” representation of what I am hoping to achieve. I have much more functionality in this and other custom attributes that I also have to support and what I am looking for is a comparable alternative to Knockout’s allBindingAccessor() in Aurelia that won’t require me to refactor a few thousand lines of code…

\*edit  
I very much appreciate your help with this question 🙂 thank you for taking the time to respond this late in the afternoon!

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [November 20, 2018, 2:28am UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/14 "2018-11-20T02:28:11Z")

</div>

Did the code I suggested work for you?

I’m not familar with knockout, but I’m still sure that what you hope to achieve can be translated fairly easily. We may just need more than some code exchange. I’m happy to help in a remote session with the help of a microphone. And some speaker or earphone.

---

<div class="post-metadata">

**Author:** ![gooeyideas](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/gooeyideas/32/64_2.png) [@gooeyideas](https://discourse.aurelia.io/u/gooeyideas)\
**Post date:** [November 20, 2018, 2:51am UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/15 "2018-11-20T02:51:06Z")

</div>

Sorry, but I already thought of the work around you suggested. As I tried to explain in my previous comment, that idea presents other problems. I have other custom attributes that work with but also independently from my custom highlight binding which help with search filtering, sorting, grouping and other nifty interactions. Refactoring the highlight binding to also control the default rendering of the text could be a massive undertaking. Not an ideal solution.

All I need is the ability to subscribe to changes of an elements attribute binding (any of them, not just textcontent) from a separate custom attribute binding.  
I don’t think a call is necessary but I am open to it if helps solve this problem.

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [November 20, 2018, 2:58am UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/16 "2018-11-20T02:58:04Z")

</div>

You can have a look at `view.bindings`, it contains all bindings of current view in the custom element. Maybe you will find what you want there, if it’s the binding that you want to find.

However, it sounds to me it’s the value of custom element view model, which ultimately all bindings / custom attributes are pointing to, is what you are after, so maybe just subscribe to it directly in your `highlight` custom attribute:

```auto
bind(customAttribute, overrideContext) {
  const customElementViewModel = this.owningView.bindingContext;
  bindingEngine.propertyObserver(customElementViewModel, 'description').subscribe(newValue => {
    // is it??
  });
}

```

---

<div class="post-metadata">

**Author:** ![gooeyideas](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/gooeyideas/32/64_2.png) [@gooeyideas](https://discourse.aurelia.io/u/gooeyideas)\
**Post date:** [November 20, 2018, 7:06pm UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/17 "2018-11-20T19:06:01Z")

</div>

So I figured out a somewhat simple solution. Injecting the TargetInstruction to get the `bindingExpression` for the target element seems to be more efficient than performing a find on the bindings array. Why does the`textcontent` have to be a `two-way` binding to work?

```javascript
//viewmodel
this.description = "this is example text content";
this.query = "example ";

```

```auto
<!-- view -->
<span textcontent.two-way="description" highlight.bind="query"></span>

```

```javascript
//custom highlight attribute
import {inject, BindingEngine, customAttribute, bindable, bindingMode, TargetInstruction} from 'aurelia-framework';

@customAttribute('highlight')
@inject(Element, BindingEngine, TargetInstruction)
export class Highlight {
  @bindable({ primaryProperty: true }) match;

  constructor(element, BindingEngine, TargetInstruction){
    this.element = element;
    this.bindingEngine = BindingEngine;
    this.bindingExpression = TargetInstruction.expressions.find((b)=> {
      return b.targetProperty === 'textContent';
    });
  }
  
  matchChanged(newValue, oldValue){
    this.update();
  }

  bind(binding, source) {
    let bindingExpression = this.bindingExpression;
    this.textcontentSub = this.bindingEngine.propertyObserver(binding, bindingExpression.sourceExpression.name).subscribe((value)=> {
      this.update(value);
    });
    this.update();
  }

  unbind(binding, source) {
    this.textcontentSub.dispose();
  }

  created(owningView, view) {
    this.view = view || owningView;
  }

  get text() {
    let bindingExpression = this.bindingExpression;
    if (bindingExpression) {
      return bindingExpression.sourceExpression.evaluate(this.view, bindingExpression.lookupFunctions);
    } else if (this.element) {
      return this.element.innerHTML;
    } else {
      return "";
    }
  }
  update(text){
    if(this.active !== false) {
      text = text || this.text
      let match = this.match;
      if (match instanceof RegExp) {
        regex = match;
      } else {      
        let matchString = match;

        matchString = matchString.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
        matchString = matchString.replace(/[a-zA-Z0-9\?\&\=\%\#]+s\=(\w+)(\&.*)?/, "$1");
        matchString = matchString.replace(/\%20|\+/g, "\|");

        regex = new RegExp("(" + matchString + ")(?=[^>]*(<|$))", "ig");
      }

      let highlightedText;
      //Call function that highlights the text
      highlightedText = highlightText(text, regex);
      let isTextHighlighted = highlightedText !== false;

      if (isTextHighlighted) {
        this.element.innerHTML = highlightedText;
      }
    }
  }
}

function highlightText(text, regex, css, style) {
  var tempText;
  var attrText;
  var matched;

  matched = false;
  tempText = text;

  attrText = ' style="font-weight: bold;"';
  // Do regex replace
  // Inject span with class and styles set with the binding

  text = tempText.replace(regex, function (match, p1, p2, offset, stringArg) {//p1, p2 Corresponds to $1, $2
    var returnReplace;
    if (typeof match === "string" && match.length > 0) {
      matched = true;
      returnReplace = '<span' + attrText + '>' + p1 + '</span>' + p2;
    } else {
      returnReplace = p1 + p2;
    }
    return returnReplace;
  });

  return matched ? text : false; //return false if nothing was changed
}

```

This is a trimmed down, working example. Is there a better way to do this?

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [November 20, 2018, 11:56pm UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/18 "2018-11-20T23:56:51Z")

</div>

Oh, I think i gave you the wrong example. Is this the property `description` you wanted to target, but you got `textcontent` from what I suggested?

---

<div class="post-metadata">

**Author:** ![gooeyideas](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/gooeyideas/32/64_2.png) [@gooeyideas](https://discourse.aurelia.io/u/gooeyideas)\
**Post date:** [November 21, 2018, 12:26am UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/19 "2018-11-21T00:26:17Z")

</div>

No, no, no, no… somewhere there is a miscommunication between what I am posting and what you are understanding.

Thank you for your help. While attempting to implement some of your suggestions I actually discovered what I needed. My previous post provides you a **working** example of the functionality I was looking to build. And I believe it is a reliable pattern for converting custom knockout bindings that rely on the `allBindingsAccessor` to the Aurelia framework.

Is there is anything wrong with the solution I found?

---

<div class="post-metadata">

**Author:** ![bigopon](https://yyz1.discourse-cdn.com/flex027/user_avatar/discourse.aurelia.io/bigopon/32/18_2.png) [@bigopon](https://discourse.aurelia.io/u/bigopon)\
**Post date:** [November 21, 2018, 1:03am UTC](https://discourse.aurelia.io/t/aurelia-alternative-for-allbindingsaccessor-method-on-custom-bindings/1910/20 "2018-11-21T01:03:02Z")

</div>

Maybe I should read the whole thing again. Maybe I was too focusing on the details. Glad you got it working though.

For your code example:

In your `.bind()`, you can rename it to :

```auto
  bind(highlightCustomAttribute) {
    // ...
  }

```

And you can see you are just listening to property `description` of it, which seems weird to me.
