user2455157
user2455157

Reputation: 147

Programmatically create binding expression

I have a scenario where an expression I wish to execute is dynamically loaded into a component. I am unable to set the expression into v-if as it is a literal string, not the actual binding expression.

I had a look at using vm.$watch however the expressions are only allowed to be dot notation paths, rather than single javascript expressions.

vm.$watch usage: Watch an expression or a computed function on the Vue instance for changes. The callback gets called with the new value and the old value. The expression only accepts simple dot-delimited paths. For more complex expression, use a function instead.

Is there some part of vuejs that I can use to achieve this? I assume that the binding expressions for the v-if directive etc are ultimately strings that are being parsed and evaluated in a given context, it just just whether these functions are available for use in components?

Hopefully this example below shows a more complete picture of what I am trying to achieve:

<template>
    <div>
        <div v-if="expression"></div>
    </div>
</template>

<script>
  export default {
    name: 'mycomponent'
    data: function() {
      var1: 5,
      var2: 7,
      expression: null
    },
    created: function() {
      this.$http.get('...').then((response) => {
        // Sample response:
        // {
        //   'expression' : 'var1 > var2'
        // }
        // TODO: Not this!!
        this.expression= response.expression;
      });
    }
  }
</script>

Upvotes: 1

Views: 1364

Answers (3)

user2455157
user2455157

Reputation: 147

Tidying up a question I have left open for over a year, the answer I have ended up using is to use the Angular Expression library Angular Expressions for my purposes, but will likely be moving to using the Friendly Enough Expression Language library in future as both my client and server will evaluate similar expressions.

Upvotes: 0

Roy J
Roy J

Reputation: 43881

Be aware that evaluating expressions requires you to use things that are Not Generally Good JavaScript, such as eval and with. Take care to ensure that you control what can get in to any use of eval.

I recommend using a computed rather than a method for this; it seems more well-suited (and avoids requiring invocation parentheses).

new Vue({
  el: '#app',
  data: {
    var1: 5,
    var2: 7,
    expression: null
  },
  computed: {
    evaluatedExpression: function() {
      with(this) {
        try {
          return eval(expression);
        } catch (e) {
          console.warn('Eval', expression, e);
        }
      }
    }
  },
  created: function() {
    setTimeout(() => {
      this.expression = 'var1 < var2';
    }, 800);
    setTimeout(() => {
      this.expression = 'var1 > var2';
    }, 2500);
  }
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.2.4/vue.min.js"></script>
<div id="app">
  {{expression}}, {{evaluatedExpression}}
  <div v-if="evaluatedExpression">
    Yep
  </div>
  <div v-else>
    Nope
  </div>
</div>

Upvotes: 0

soju
soju

Reputation: 25312

You could create a method for this, e.g. :

<div v-if="testExpression"></div>

And add methods in your component config :

methods: {
    testExpression() {
        return eval(this.expression)
    }
}

Upvotes: 1

Related Questions