Still pretty new to Ember. I am trying to use the component Ember helper to overwrite a function on the component.
My component looks like:
Ember.Component.extend({
...
getValue() {...}
...
});
I have another component with a template that looks like:
<div>
{{component myComponentName getValue=(action myCustomGetValue)}}
</div>
I would imagine that this would overwrite the getValue function from the original component, but it does not. Is this possible using this helper to do this? Or am I going about this the wrong way?
Yes, you can pass function references to component helpers in Emberjs.
You can call your component through component helper like:
{{component "my-component" getValue=(action "myCustomGetValue")}}
in which case you should define the custom action in your parent component or controller like:
actions: {
myCustomGetValue(){
return "my custom value";
}
}
You can take a look at this twiddle for this usage.
Related
I wanted my directive to work as v-if since in my directive I have to check access rights and destroy the element if it does not have access.
Here is my code
Vue.directive('access', {
inserted: function(el, binding, vnode){
//check access
if(hasAccess){
vnode.elm.parentElement.removeChild(vnode.elm);
}
},
});
vue file
<my-component v-access='{param: 'param'}'>
The issue is that i'm applying this directive to a component, it's removing the component but not the execution of functions called by the created/mounted hook.
In the component(my-component) there are functions in mounted/created hook. The execution of these functions are done and I don't want these functions to be executed. Is there a way to stop execution of the mounted/created events?
It is impossible to replicate the behavior of v-if in a custom directive. Directives cannot control how vnodes are rendered, they only have an effect on the DOM element it is attached to. (v-if is special, it's not actually a directive but instead generates conditional rendering code when the template is compiled.)
Though I would avoid doing any of the following suggestions if possible, I'll provide them anyway since it's close to what you want to do.
1. Extend the Vue prototype to add a global method
You definitely need to use v-if to do the conditional rendering. So all we have to do is come up with a global helper method which calculates the access permission.
Vue.prototype.$access = function (param) {
// Calculate access however you need to
// ("this" is the component instance you are calling the function on)
return ...
}
Now in your templates you can do this:
<my-component v-if="$access({ param: 'param' })">
2. Define global method in the root component
This is basically the same as #1 except instead of polluting the Vue prototype with garbage, you define the method only on the root instance:
new Vue({
el: '#app',
render: h => h(App),
methods: {
access(param) {
return ...
}
}
})
Now in your templates you can do this:
<my-component v-if="$root.access({ param: 'param' })">
Now it's clearer where the method is defined.
3. Use a global mixin
This may not be ideal, but for what it's worth you can investigate the viability of a global mixin.
4. Use a custom component
You can create a custom component (ideally functional but it needn't be) that can calculate access for specific regions in your template:
Vue.component('access', {
functional: true,
props: ['param'],
render(h, ctx) {
// Calculate access using props as input
const access = calculateAccess(ctx.props.param)
// Pass the access to the default scoped slot
return ctx.scopedSlots.default(access)
}
})
In your templates you can do this:
<access :param="param" v-slot="access">
<!-- You can use `access` anywhere in this section -->
<div>
<my-component v-if="access"></my-component>
</div>
</access>
Since <access> is a functional component, it won't actually render it's own component instance. Think of it more like a function than a component.
A bit overkill for your situation, but interesting nonetheless if you ever have a more complicated scenario.
I have a component called ShowComment and a component called EditComment.
In ShowComment there is a variable this.CommentRecID. I want to use this variable in the component EditComment.
The problem is that a console.log(this.CommentRecID); shows that the variable is undefined in EditComment, but defined in ShowComment, but I don't know why it's undefined:
I used this to "use" this.CommentRecID in EditComment, but I don't know if this is the correct way to do it because it's related to jquery:
import * as $ from "jquery";
import DatePicker from "vue2-datepicker";
export default {
props: ["CommentRecID"],
components: { DatePicker },
Here's the full ShowComment component: https://pastebin.com/fcy4PCq0
Here's the full Editcomment component: https://pastebin.com/uik7EwD1
I'm fairly new to Vue.js. Does someone know how one can solve this issue?
You should not use jQuery and Vue.js at the same time.
You should try to use props to send data from parent to child.
You could add EditComment as an element in your ShowComment something like this:
<EditComment CommentRecID="this.CommentRecID" v-if="showEdit" />
And toggle the showEdit flag from the editItem method
editItem() {
this.showEdit = true
}
If you want to show a modal, then your EditComment component is probably up the tree so you could either use EventBus or use Vuex.
It seems like you are already using Vuex in your project, so add a mutation that stores the CommentRecID and use it in a similar manner to show the dialog.
You can use Vue Props to easily solve this problem, you have to send the variable from parent component to child component, please check this PROPS documentation out, its self explanatory:
Props Vuejs documentation
please let me know if you find trouble in using props
I had a case when I need to call a child function in my App.js component.
The short schema look like this :
Where I need to call the function() from the App.js, and the the function triggers something directly inside the Child 3 component.
I'm avoiding using function props drilling from the parent where this could be another problem in the future.
I tried to use Redux to dispatch the function into store, but Redux doesn't allow non-object properties to be stored.
Any help would be appreciated!
I have an ember route that calls an ember component to display all the data.
I have a case in which the route's key changes and I reload using route.transitionTo. The data is loaded fine. But the problem is the component does stuff in the init and didInsertElement methods, which on the route.transitionTo aren't triggered.
How can I make sure on transitionTo the component is called again?
I can't use route.refresh because that doesn't do the model hook.
Any help will be appreciated, Thank you!
Well, there is a harder and better way, and there is a lazy and fast way:
Better way: I suggest you to create a property in the route and pass this parameter to the component, and in the component create a computed property for that parameter, what you've sent, and there you can run your code what you called in "init" and "didInsertElement" function.
E.g.:
router.hbs
{{component-name parameter=parameter}}
Component.js
lineWidth: Ember.computed('parameter', function() {
// I will run here if I get the parameter (and the parameter changed in route)
}),
Not the best way:
You can reload the whole component like this:
router.hbs
{{#if reload}}
{{component-name}}
{{/if}}
router.js
this.set('reload', false);
Ember.run.next(() => {
this.set('reload', true);
});
I am new to Ember and noticed the following code in my Handlebars:
{{component sec.myCompRef secInfo=sec fields=model.myMap}}
Does Ember have some helper like {{component}}? If yes, how does it work?
I have generally seen custom helper:
{{my-helper}}
But that has the same name component hbs/js backing it?
But I am not aware of {{component}} helper.
Yes, Ember has {{component}} helper which allows you to dynamically choose and render component via component name passed to {{component}} helper.
So, basically the usage is:
{{component componentName}}
You can of course pass arguments and data to it like you would do with casual component declaration:
{{component componentName model=whatever}}
So, in your case:
{{component sec.myCompRef secInfo=sec fields=model.myMap}}
sec.myCompRef is the name of component to render (it has to match some existing component)
secInfo and fields are parameters passed to component