# \[Solved\] How to use virtual-dom's "h" helper in \<head\> for header-dropdown hamburger widget override? + How to override @computed method?

**URL:** https://meta.discourse.org/t/solved-how-to-use-virtual-doms-h-helper-in-head-for-header-dropdown-hamburger-widget-override-how-to-override-computed-method/104583
**Category:** Development
**Created:** [December 18, 2018, 6:50pm UTC](https://meta.discourse.org/t/solved-how-to-use-virtual-doms-h-helper-in-head-for-header-dropdown-hamburger-widget-override-how-to-override-computed-method/104583 "2018-12-18T18:50:30Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![rbrlortie](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rbrlortie/32/166740_2.png) [@rbrlortie](https://meta.discourse.org/u/rbrlortie)
#### Post date: [December 18, 2018, 6:50pm UTC](https://meta.discourse.org/t/solved-how-to-use-virtual-doms-h-helper-in-head-for-header-dropdown-hamburger-widget-override-how-to-override-computed-method/104583/1 "2018-12-18T18:50:30Z")

</div>

Hi,

I’m attempting to override the main header-dropdown html tags via my custom theme.

My proof on concept was this:

```plaintext
<script type="text/discourse-plugin" version="0.8.23">
api.reopenWidget("header-dropdown", {
  html(attrs) {
    if (attrs.icon == 'bars') {
        return 'TEXT TO RETURN INSTEAD OF HAMBURGER';
    } else {
        return this._super(attrs);
    }
  }
});
</script>

```

In this example, ‘`TEXT TO RETURN INSTEAD OF HAMBURGER`’ displays correctly.

Now, I want to wrap this text with a tag.

The solution seems to use the `h` helper like so:

```plaintext
 return h('b', "TEXT TO RETURN INSTEAD OF HAMBURGER");

```

However, this returns `ReferenceError: h is not defined`.

Attempting to add `import { h } from "virtual-dom";` doesn’t work, which makes sense because I’m in the custom theme head override. (`/admin/customize/themes/7/common/head_tag/edit`)

What would be the correct way to do this without creating a plugin?

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [December 18, 2018, 6:52pm UTC](https://meta.discourse.org/t/solved-how-to-use-virtual-doms-h-helper-in-head-for-header-dropdown-hamburger-widget-override-how-to-override-computed-method/104583/2 "2018-12-18T18:52:15Z")

</div>

You can access the helper from a theme by putting this at the top of the javascript:

```plaintext
const h = require("virtual-dom").h;

```

---

<div class="post-metadata">

### Author: ![rbrlortie](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rbrlortie/32/166740_2.png) [@rbrlortie](https://meta.discourse.org/u/rbrlortie)
#### Post date: [December 18, 2018, 7:01pm UTC](https://meta.discourse.org/t/solved-how-to-use-virtual-doms-h-helper-in-head-for-header-dropdown-hamburger-widget-override-how-to-override-computed-method/104583/3 "2018-12-18T19:01:09Z")

</div>

I love you! Thanks 🥰

---

<div class="post-metadata">

### Author: ![rbrlortie](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rbrlortie/32/166740_2.png) [@rbrlortie](https://meta.discourse.org/u/rbrlortie)
#### Post date: [December 18, 2018, 8:20pm UTC](https://meta.discourse.org/t/solved-how-to-use-virtual-doms-h-helper-in-head-for-header-dropdown-hamburger-widget-override-how-to-override-computed-method/104583/4 "2018-12-18T20:20:57Z")

</div>

@david

Another things that I’m trying to do, if you have an answer that will avoid the need to create a separate topic.

* * *

I want to throw a validation message when the user only chooses one level of category.

I was attempting to override `categoryValidation()` of composer.js.es6 … except that is a @computed method.

Looking at [https://github.com/discourse/discourse-assign/blob/master/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6#L69](https://github.com/discourse/discourse-assign/blob/master/assets/javascripts/discourse-assign/initializers/extend-for-assigns.js.es6#L69) this should be doable.

**My issue is that from the `<head>`, I don’t have acces to `@computed`. Is there a way to require it?**

I did manage to override the `controller:composer` save action. However, from there I don’t have access to `InputValidation` to throw a custom error (I wouldn’t know how to target the correct input from there either).

```plaintext
<script type="text/discourse-plugin" version="0.8.23">
    api.modifyClass('controller:composer', {
        @computed("model.categoryId", "lastValidatedAt") //ReferenceError: computed is not defined
        categoryValidation() {
            console.log('categoryValidation');
            this._super();
        }
    });
</script> 

```

---

<div class="post-metadata">

### Author: ![simon](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/simon/32/339122_2.png) [@simon](https://meta.discourse.org/u/simon)
#### Post date: [December 18, 2018, 8:40pm UTC](https://meta.discourse.org/t/solved-how-to-use-virtual-doms-h-helper-in-head-for-header-dropdown-hamburger-widget-override-how-to-override-computed-method/104583/5 "2018-12-18T20:40:30Z")

</div>

> [@rbrlortie](#):
>
> I was attempting to override `categoryValidation()` of composer.js.es6 … except that is a @computed method.

I’m not sure if this is the only way to do it, but I’ve modified computed properties in customizations like this (the example is using the `availableSorts` computed property):

```plaintext
 api.modifyClass('component:edit-category-settings', {
    availableSorts: Ember.computed(function() {
    let sorts = this._super();
    let voteSort = {};
    voteSort["name"] = "Votes";
    voteSort["value"] = "votes";
    sorts.push(voteSort);
    return sorts;
    })
  });

```

---

<div class="post-metadata">

### Author: ![david](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/david/32/157490_2.png) [@david](https://meta.discourse.org/u/david)
#### Post date: [December 18, 2018, 8:53pm UTC](https://meta.discourse.org/t/solved-how-to-use-virtual-doms-h-helper-in-head-for-header-dropdown-hamburger-widget-override-how-to-override-computed-method/104583/6 "2018-12-18T20:53:24Z")

</div>

If you want to use the decorator syntax, you can do this

```plaintext
const computed = require("ember-addons/ember-computed-decorators").default;

```

Then you can do

```plaintext
api.modifyClass('component:edit-category-settings', {
    @computed("model.categoryId", "lastValidatedAt")
    availableSorts(categoryId, lastValidatedAt){
        let sorts = this._super();
        let voteSort = {};
        voteSort["name"] = "Votes";
        voteSort["value"] = "votes";
        sorts.push(voteSort);
        return sorts;
    }
  });

```

Notice that these lines are just a re-arranging of the `import` lines that you see in Discourse’s codebase. So anything you can import, you should be able to `require` in a theme.

---

<div class="post-metadata">

### Author: ![rbrlortie](https://sea3.discourse-cdn.com/meta/user_avatar/meta.discourse.org/rbrlortie/32/166740_2.png) [@rbrlortie](https://meta.discourse.org/u/rbrlortie)
#### Post date: [December 18, 2018, 9:13pm UTC](https://meta.discourse.org/t/solved-how-to-use-virtual-doms-h-helper-in-head-for-header-dropdown-hamburger-widget-override-how-to-override-computed-method/104583/8 "2018-12-18T21:13:13Z")

</div>

Awesome, this worked really well!

* * *

Here is the snippet for the composer window’s categoryValidation override, if anyone stumble here using the search.

```plaintext
<script type="text/discourse-plugin" version="0.8.23">
const computed = require("ember-addons/ember-computed-decorators").default;
api.modifyClass('controller:composer', {
    @computed("model.categoryId", "lastValidatedAt")
    categoryValidation(categoryId, lastValidatedAt) {
        var InputValidation = require("discourse/models/input-validation").default;
        var categoryDepth = /*Find categoryId's category level*/;
        if(this.get('model').draftKey == "new_topic" && (categoryDepth !== 0 && categoryDepth < 2)) {
            return InputValidation.create({
                failed: true,
                reason: 'You need to select a subcategory',
                lastShownAt: lastValidatedAt
              }); //THIS WORKS AND DISPLAY AN CUSTOM ERROR MESSAGE
        } else {
            return this._super(categoryId, lastValidatedAt);
        }
    }
});
</script>

```
