How to get dom objects in dijit ContentPane content - dojo

There is one image in dojo/dijit's content. I want to set click event for the image but it can't catch the event.
the code in JSFiddle
<script>dojoConfig = {parseOnLoad: true}</script>
<script src='../../_static/js/dojo/dojo.js'></script>
<script>
require(["dijit/layout/ContentPane", "dojo/domReady!"], function(ContentPane){
new ContentPane({
content:"<p><img src='https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/logo_white_fe6da1ec.png' onclick='clickHandler()' /></p>",
style:"height:125px"
}, "targetID").startup();
function clickHandler()
{
alert("img clicked");
}
});
</script>
</head>
<body class="claro">
<div id="targetID">
I get replaced.
</div>
</body>
</html>

You are defining the clickHandler function within the require function. This means that it will not be available after require returns. At the console you can see an error when the image is clicked: "clickHandler is not defined". You can easily solve this by defining the clickHandler function outside of require().
<script>
require(["dijit/layout/ContentPane", "dojo/domReady!"], function(ContentPane){
new ContentPane({
content:"<p><img src='https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/logo_white_fe6da1ec.png' onclick='clickHandler()' /></p>",
style:"height:125px"
}, "targetID").startup();
});
function clickHandler()
{
alert("img clicked");
}
</script>

Edited.
require([
'dojo/dom-construct',
'dijit/layout/ContentPane',
'dojo/domReady!'
], function(domConstruct, ContentPane){
new ContentPane({
content: '<div id="imageDiv"></div>',
style: 'height:125px'
}, 'targetID').startup();
domConstruct.create('img', {
src: 'https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superman/img/logo/logo_white_fe6da1ec.png',
onclick: function(){ alert('i have been clicked') }
}, 'imageDiv');
});
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"></script>
<div id="targetID">I get replaced.</div>

Related

How to use href in Vue and Quill

I am using the Quill editor in Vue.js and it's working great. I have images, etc.
But...the link isn't working. I tried both the "snow" and "bubble" themes.
I type the text, highlight it and then click on the "link". I get the dialog to set the link, but then the link isn't there.
It's working in the JavaScript version, but not the Vue.
Below is my code.
Vue.component('editor', {
template: '<div ref="editor"></div>',
props: {
value: {
type: String,
default: ''
}
},
data: function() {
return {
editor: null
};
},
mounted: function() {
this.editor = new Quill(this.$refs.editor, {
modules: {
toolbar: [
[{ header: [1, 2, 3, 4, false] }],
['bold', 'italic', 'underline'],
['image', 'code-block', 'link']
]
},
//theme: 'bubble',
theme: 'snow',
formats: ['bold', 'underline', 'header', 'italic', 'link'],
placeholder: "Type something in here!"
});
this.editor.root.innerHTML = this.value;
this.editor.on('text-change', () => this.update());
},
methods: {
update: function() {
this.$emit('input', this.editor.getText() ? this.editor.root.innerHTML : '');
}
}
})
new Vue({
el: '#root',
data: {
//model: 'Testing an editor'
model: '',
isShowing: true
}
})
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
<link href="https://cdn.quilljs.com/1.3.4/quill.snow.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<link href="https://cdn.quilljs.com/1.3.4/quill.core.css" rel="stylesheet"/>
<!DOCTYPE html>
<html>
<head>
<title>Trying to use the Quill Editor in Vue</title>
</head>
<body>
<div id="root">
<div v-if="isShowing">
<editor v-model="model"></editor>
</div>
<p>I need the v-html directive: <span v-html="model"></span></p>
<p>Raw data: <pre>{{ model }}</pre></p>
<button #click="isShowing = !isShowing">Toggle</button>
</div>
</script>
</body>
</html>
Any help is greatly appreciated.
Thanks, D
I had to place a 'link' into the "formats" as well:
formats: ['bold', 'underline', 'header', 'italic', 'link'],
I updated my code snippet with the correct answer in case anyone else is having this problem.
Thanks!

How to get Vue to catch event?

Edited to correct unreported syntax error (see comments). It now works as desired.
I'm having trouble getting my event handler to fire in the following Vue code.
As you see, there are two components, posts and post, and a root Vue instance. The button in the post template should fire the remove event, which is captured by the v-on:remove handler in posts which calls posts.deleteItem with the index of the post. Can someone give me a hint what I'm doing wrong?
<!DOCTYPE html>
<html lang="en">
<head>
<title>Posts</title>
<!--link href="../css/bootstrap.css" rel="stylesheet" /-->
<script src="../vue.js"></script>
</head>
<body>
<div id="app">
<posts></posts>
</div>
<script>
window.onload = function() {
// A post
Vue.component('post-item', {
props: ['post'],
data: function() {
return {
editing: false,
_cachedItem: ''
}
},
methods: {
deleteItem(postId) {
debugger
this.$emit('remove', event.target.value);
},
},
template: `
<div v-on:remove="deleteItem">
<li v-show="!editing">
<p v-html="post.text"></p>
<button v-on:click="$emit('remove')">Delete</button>
</li>
</div>
`
})
Vue.component('posts', {
data: function() {
return {
posts: [
{id: 0, text: "Day at beach"},
{id: 1, text: "Carving the canyons"},
{id: 2, text: "Kickin' it"}
],
};
},
methods: {
deleteItem(index) {
debugger
this.posts.splice(index, 1);
}
},
template: `
<div>
<ol>
<post-item
v-for="(post, index) in posts"
v-bind:post="post"
v-bind:key="post.id"
v-on:remove="deleteItem(index)" />
</ol>
</div>
`
});
// Root Vue instance
new Vue({
el: '#app'
});
}
</script>
</body>
</html>
Looks like you're getting a little confused with the event creation and handling.
Events are emitted up to parent components. You don't typically add an event listener within the same component.
All you really need in your post-item component is to emit the remove event with the appropriate data (ie, the post object)
<div>
<li v-show="!editing">
<p v-html="post.text"></p>
<button #click="$emit('remove', post)">Delete</button>
</li>
</div>
Then in your parent component (posts), listen for this event on the post-item component and assign the event handler
<post-item v-for="post in posts" :key="post.id" :post="post" #remove="deleteItem" />
and handle the event with post payload
methods: {
deleteItem (post) {
this.posts.splice(this.posts.indexOf(post), 1)
}
}
The post object emitted by the post-item component should be the very same object passed in to its prop which is why you can directly use this.posts.indexOf(post). There's no need to go searching for matching id properties.

Vue.js: Why won't my data display in this list containing multiple component types?

I am trying to get to a point where I can have multiple component types being rendered within a single parent. It's not something which is easy to search for answers on.
I know that it is differentiating the components by adding something to the templates to distinguish them, but if I pass data as you'll see below, I get nothing, any tips?
Edit: I also don't want to have to render out these components in the HTML for this to work, needs to be passed in via JS.
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="app">
<component v-for="widget in widgets" :is="widget.type"></component>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.js"></script>
<script>
Vue.config.debug = true
Vue.component('component-a', {
template: '<p>{{foo}}</p>',
props: ['foo',]
});
Vue.component('component-b', {
template: '<p>{{bar}}</p>',
props: ['bar',]
});
new Vue({
el: "#app",
data: {
widgets: [
{
type: "component-a",
foo: 'Hello'
},
{
type: "component-b",
bar: "World",
},
]
}
});
</script>
</body>
</html>
The issue is that you're not passing any props for the foo and bar elements
<!doctype html>
<html>
<head>
<title></title>
</head>
<body>
<div id="app">
<component v-for="widget in widgets" :is="widget.type" :foo="widget.foo" :bar="widget.bar"></component>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.js"></script>
<script>
Vue.config.debug = true
Vue.component('component-a', {
template: '<p>{{foo}}</p>',
props: ['foo',]
});
Vue.component('component-b', {
template: '<p>{{bar}}</p>',
props: ['bar',]
});
new Vue({
el: "#app",
data: {
widgets: [
{
type: "component-a",
foo: 'Hello'
},
{
type: "component-b",
bar: "World",
},
]
}
});
</script>
</body>
</html>
jsFiddle
In your example the components are rendering with empty strings so you're not seeing the values you're trying to pass. when using interchangeable components it's often best to use a common value interface. Something along the lines of:
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="app">
<component v-for="widget in widgets" :is="widget.type" :value="widget.value"></component>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.js"></script>
<script>
Vue.config.debug = true
Vue.component('component-a', {
template: '<p>{{value.foo}}</p>',
props: ['value',]
});
Vue.component('component-b', {
template: '<p>{{value.bar}}</p>',
props: ['value',]
});
new Vue({
el: "#app",
data: {
widgets: [
{
type: "component-a",
value: {
foo: 'Hello'
}
},
{
type: "component-b",
value: {
bar: "World",
}
},
]
}
});
</script>
</body>
</html>
So that the components only pass the single value object to the component necessary and the component pulls the unique values from that object.

Can't change button text inside setTimeout function

I have got follow Vue-js App:
<html>
<head>
<script src="https://cdn.jsdelivr.net/vue/1.0.26/vue.min.js"></script>
<style>
.mydiv
{
border: 1px black dashed;
font-size: 2em;
}
</style>
<script>
var App = null; // it's global because function behind will overwrite it's with Vue App instance
window.onload = function()
{
new Vue(
{
el: '#app',
data:
{
btntext: "OK"
},
methods:
{
change: function()
{
this.btntext = "cancel";
setTimeout(function() {console.log("test"); this.btntext = "text changed";},1000);
}
}
})
}
</script>
</head>
<body>
<div id="app">
<div class="mydiv">
<button v-on:click="change">{{btntext}}</button>
</div>
</div>
</body>
</html>
After running I am getting "test" on console, but button do not change it's text to text changed. Why?
The function given to setTimeout does not have the same "this" as your Vue. You could use the bind function:
new Vue({
el: '#app',
data: {
btntext: "OK"
},
methods: {
change: function () {
this.btntext = "cancel";
setTimeout(function () {
console.log("test");
this.btntext = "text changed";
}.bind(this), 1000);
}
}
})
.mydiv{
border: 1px black dashed;
font-size: 2em;
}
<script src="https://cdn.jsdelivr.net/vue/1.0.26/vue.min.js"></script>
<div id="app">
<div class="mydiv">
<button v-on:click="change">{{btntext}}</button>
</div>
</div>
You have to understand the context of this keyword. When in setTimeout callback function, this refers to different object that this before it. To solve this issue, you should solve reference to this before the callback or if you're going to use ES2015, you can change function () {...} with arrow function () => {...}, which will automatically save reference to outer this and use it instead of actual this inside the function. But if you're going to use that, make sure it's supported across all your target browsers, or alternatively use a compiler to ES5, most popular of which is Babel.

how to remove row from dgrid

I have defined dgrid and a button for removing row:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="http://cdn.rawgit.com/SitePen/dgrid/v1.1.0/css/dgrid.css" media="screen" />
</head>
<body class="claro">
<div id="container"></div>
<button id="remove">Remove</button>
<script type="text/javascript">
var dojoConfig = {
async: true,
packages: [
{ name: 'dgrid', location: '//cdn.rawgit.com/SitePen/dgrid/v1.1.0' },
{ name: 'dstore', location: '//cdn.rawgit.com/SitePen/dstore/v1.1.1' }
]
};
</script>
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"></script>
<script type="text/javascript">
require([
'dojo/_base/declare',
'dojo/on',
"dojo/dom",
"dstore/Memory",
"dstore/Trackable",
'dstore/SimpleQuery',
'dgrid/Grid',
'dgrid/extensions/Pagination',
'dgrid/extensions/DijitRegistry',
'dojo/domReady!'
],
function(declare, on, dom, Memory, Trackable, SimpleQuery, Grid, Pagination, DijitRegistry) {
var data = [];
for (var i = 1; i <= 500; i++) {
data.push({id:i,name: 'Name '+i, value: i});
}
var Store = declare([Memory, SimpleQuery, Trackable]);
var myStore = new Store({data:data});
var MyGrid = declare([Grid, Pagination]);
var grid = new MyGrid({
collection: myStore,
columns: {
'id' : 'Id',
'name' : 'Name',
'value' : 'Value'
},
className: "dgrid-autoheight",
showLoadingMessage: false,
noDataMessage: 'No data found.'
}, 'container');
grid.startup();
on(dom.byId('remove'),'click',function() {
myStore.remove(10);
});
});
</script>
</body>
</html>
The dgrid shows up, you can sort it, edit name or value.
The problem is, that when you click on the "remove" button, row is deleted, but then, at the end of the gird is 9x written: "No data found" and the dgrid stops to work (you cant delete any other row).
If you set showLoadingMessage: to true, then everything works without a problem.
Edit: I have simplified the example. Problem persists.
The grid may have been encountering error while updating the row data after the row has been removed. As the editor tries to update the row after the button loses focus. Try using the grid.removeRow method to remove the row. It might still encounter some other issues, but worth a try.
Editor might not be the best solution to achieve what your are trying to do.
User renderCell to add button to the grid, to remove the row/record. This might be a better solution.
Update: Just refresh the grid that should solve the problem.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<link rel="stylesheet" href="http://cdn.rawgit.com/SitePen/dgrid/v1.1.0/css/dgrid.css" media="screen" />
</head>
<body class="claro">
<div id="container"></div>
<button id="remove">Remove</button>
<script type="text/javascript">
var dojoConfig = {
async: true,
packages: [
{ name: 'dgrid', location: '//cdn.rawgit.com/SitePen/dgrid/v1.1.0' },
{ name: 'dstore', location: '//cdn.rawgit.com/SitePen/dstore/v1.1.1' }
]
};
</script>
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.4/dojo/dojo.js"></script>
<script type="text/javascript">
require([
'dojo/_base/declare',
'dojo/on',
"dojo/dom",
"dstore/Memory",
"dstore/Trackable",
'dstore/SimpleQuery',
'dgrid/Grid',
'dgrid/extensions/Pagination',
'dgrid/extensions/DijitRegistry',
'dojo/domReady!'
],
function(declare, on, dom, Memory, Trackable, SimpleQuery, Grid, Pagination, DijitRegistry) {
var data = [];
for (var i = 1; i <= 500; i++) {
data.push({id:i,name: 'Name '+i, value: i});
}
var Store = declare([Memory, SimpleQuery, Trackable]);
var myStore = new Store({data:data});
var MyGrid = declare([Grid, Pagination]);
var grid = new MyGrid({
collection: myStore,
columns: {
'id' : 'Id',
'name' : 'Name',
'value' : 'Value'
},
className: "dgrid-autoheight",
showLoadingMessage: false,
noDataMessage: 'No data found.'
}, 'container');
grid.startup();
on(dom.byId('remove'),'click',function() {
myStore.remove(10);
grid.refresh();
});
});
</script>
</body>
</html>