I'm trying to dynamically render some HTML in a Vue.js component. I'm successfully rendering the HTML. However, I don't know how to wire-up the events for the dynamically rendered elements. I've created a small example. This example probably looks like I've over complicated things. However, it's just a small part of the real example. The example can be seen in this JSFiddle, and the code looks like this:
new Vue({
el: '#app',
data: {
items: [
{
name:'Item 1',
isHtml:true,
mold: function() {
return '<button #click="onButtonOneClick">click</button>';
}
},
{
name: 'Item 2',
isHtml: false
},
{
name:'Item 3',
isHtml: true,
mold: function() {
return '<button #click="onButtonThreeClick">click</button>';
}
}
]
},
methods: {
getHtml: function(i) {
return i.mold();
},
onButtonOneClick: function() {
alert('First Item Clicked');
},
onButtonThreeClick: function() {
alert('Third Item Clicked')
}
}
})
If you run this fiddle, you'll notice that my two buttons look fine on the screen. However, the related click events don't get fired when you actually click the buttons. From what I can see, it looks like the HTML doesn't get fully compiled. I may be wrong. But, it's what it looks like based on what i see in the Chrome Dev Tools.
How do I wire up events for dynamically generated HTML in a Vue.js component?
You're trying to render 'functional html' which is basically the essence of what Vue does for you. Just render your list as you do, and add in your data in an attribute like 'is_button', and output the html for the button in the v-for and add its events. e.g.
<div v-for="(item, index) in items">
<button v-if="item.is_button" #click="onButtonClick(index)">
<div>item.content</div>
</div>
Good luck
Your example goes against everything that Vue is trying to accomplish. I suggest reading up on Vue in their docs or following some tutorials. I am not saying it can't be done because you could certainly bind events later but it is not wise.
Certainly something like this is not going to work:
mold: function() {
return '<button #click="onButtonThreeClick">click</button>';
}
That is because Vue has already rendered the markup when you inject this.
It is difficult to tell what you are trying to achieve exactly but perhaps something like this can help you out:
https://jsfiddle.net/ozf8kq1z/2/
(Open your console)
I'm sorry to be a nuisance, but why have you got vue markup in your data :? This is never going to work. Can you explain what led you down this path? Why can't your markup stay in a template :?
Vue does have a v-html directive for popping little bits of markup out of javascript into templates, but Vue tags in this markup are not processed, and it's one of those features you should use with a bad conscience.
Event listeners outside of Vue, attached after Vue has rendered, do function, but then you've really got to look at yourself in the mirror and ask "oh what have I done"?
Related
I'm building a Svelte component library to be consumed using JavaScript only. At a later stage also by other Svelte applications as an additional option.
I want to avoid Svelte's custom element feature, since there are limitations with true Web Components and its Shadow DOM.
Currently the component is instantiated like this:
<div id="my-component"></div>
<script>
document.addEventListener("DOMContentLoaded", function (event) {
new MySvelteComponent({
target: document.getElementById("my-component"),
props: {
firstProp: true,
secondProp: "some value"
}
});
});
</script>
Now I would like to provide a more elegant way by defining a HTLM5 custom tag like:
<my-component firstProp="true" secondProp="some value">
What is a good way to implement this?
found it: github/svelte-tag npm/svelte-tag
see regarding issue on github near to the bottom is the answer from chrisward.
It makes a custom element but without shadow DOM. Found it today and workes for me.
I'm using Fullcalendar v5 in angular js, and i'm trying to make a custom event with:
https://fullcalendar.io/docs/content-injection
eventContent: function(arg) {
return { html: constructEvent(arg) }
},
The thing is that if i add:
"<div ng-repeat='user in arg.event._def.extendedProps.users' class='avatar'>"
"<p>{{ user.name }}</p>"
"</div>"
it won't render. It's like it's outside angular's scope. Can someone tell me if there is a way to construct this with angular js logic? Or i need to use vanilla js to iterate through items. Also ng-click doens't work. I tried even with triggering safeApply digest but no results.
I just want to edit the event inside calendar with the framework i'm using, and use angular events inside it to open sidebars or to make api calls.
Rendering Events
with your line <div ng-repeat it seems that you'd like to iterate through an array of events to display on your screen. If this is the case, you simply need to render the events via the 'events' parameter.
https://fullcalendar.io/docs/event-object
Regarding eventContent (the contents of an event, such as title, subtitle, img, etc)
It looks like at the minute only React JSX Nodes are supported. Vanilla JS is your only way forward.
https://fullcalendar.io/docs/content-injection
I have just started learning vue2. While playing with components and custom-event, i am facing a problem. I am expecting an alert with text caught but nothing happens. Below is the simple code:
<div class="container" id="app" >
<div v-on:newmessage="handleNewMessage">
<message></message>
</div>
</div>
<script>
Vue.component('message',{
template: '<input type="text" #keyup.enter="handleInput">',
methods: {
handleInput: function(event)
{
this.$emit('newmessage');
},
}
});
var demo = new Vue({
el: '#app',
methods: {
handleNewMessage: function(message)
{
alert('caught');
}
},
});
</script>
Please note that if i move the newmessage event listener from the div element to the message element, this works fine and the alert is generated:
//this works
<div >
<message v-on:newmessage="handleNewMessage"></message>
</div>
I might as well be missing something very basic here. Do custom events not propagate up to native dom parent elements? I spent whole evening searching for a reference but no luck.
Thanks in advance.
Yes, it works as you explained since $emit is only visible at <message> tag (as I know it) and NOT at the <div> enclosing it. You can try directly emitting to the root component (#app) and wire the handler there too.
this.$root.$emit('newmessage')
and,
<div class="container" id="app" v-on:newmessage="handleNewMessage">
(EDIT)and,
const component = Vue.component('message' ...)
new Vue({
el: '#app',
components: component
...)
Basically, you are not doing anything wrong here.
PS: I haven't run EDIT. But, the idea is along those lines. Let me know if that works.
Unlike components and props, event names will never be used as variable or property names in JavaScript, so there’s no reason to use camelCase or PascalCase. Additionally, v-on event listeners inside DOM templates will be automatically transformed to lowercase (due to HTML’s case-insensitivity), so v-on:myEvent would become v-on:myevent – making myEvent impossible to listen to.
For these reasons, we recommend you always use kebab-case for event names.
I'm very new to both Ember and web development. Let's say that I'm building a site that displays news articles. I'd like some interaction with Wikipedia links in each article so that when you click on them, a little box will pop up in place with the summary (like the Instapaper app). I'd also like some interaction within the box, expanding and collapsing the summary, etc. What is the most Ember-like way to do this?
I think that with jQuery it would be trivial to add a click handler to the links to add the box to the DOM, but I'd really like the box to be an Ember view. I thought I might have been able to create a view dynamically and append it to a DOM element but it seems that it isn't allowed, and you can only append to ContainerViews.
How should I approach this?
Update on what I've tried
Essentially, I have this as a template for each article so there are paragraphs and a container on the right of each paragraph for the boxes:
{{#each paragraph}}
<div class='paragraph-container'>
<p {{bind-attr id=paragraph_id}}>{{html_text}}</p>
<div class='paragraph-reference-container' {{bind-attr id=paragraph_reference_id}}></div>
</div>
{{/each}}
And an associated view. paragraph_reference_id and paragraph_id are computed properties so I can set the IDs properly here. I also have a ReferenceView for the boxes, which is uninteresting since it's just placeholder content and code at the moment. I was racking my brain trying to figure this out, and ended up trying something like this to append the view as was in the documentation:
App.ArticleView = Ember.View.extend({
templateName: 'article',
classNames: ['articles'],
didInsertElement: function () {
var container = this.container;
Ember.run.scheduleOnce('afterRender', this, function () {
var em = this;
em.$('.paragraph-container').each(function () {
var referenceContainerID = $('.paragraph-reference-container', this).first().prop('id');
em.$('a.wikipedia-link', this).click(function () {
var referenceView = container.lookup('view:reference');
referenceView.appendTo('#' + referenceContainerID);
});
});
});
}
});
But I got the "Uncaught Error: Assertion Failed: You cannot append to an existing Ember.View. Consider using Ember.ContainerView instead." error. Apparently this is no longer supported as mentioned above. I don't really know what the "Ember" way is to do this and still use views (which I'd really like to do) instead of plain HTML and jQuery.
I just wanted to get the HTML from a ReactJS component. I use a jquery module that need some HTML as parameter. I'm using coffeescript and ReactJS for the rest of the application.
Action = React.createClass
render: -> [...]
componentDidMount: ->
$(myJQueryModule).action(
html: $(#props.html).html()
)
Action
html: React.DOM.span {className: "test"}, "test of text"
Btw, this is not working and I have some troubles to understand why. Can someone help :) ?
Ty
A component doesnt get rendered to text like that, You probably want to use http://facebook.github.io/react/docs/top-level-api.html#react.rendercomponenttostring
But is wont have any React integrations and events etc, so you might be better by just use normal HTML in a string to feed to the jquery.