Include an input field in a Tippy tooltip - input

I simply use Tippy capability to have an input field included in the tooltip.
Everything works fine, except that it is impossible to write anything in the input field.
Is it possible to do it? How?
Here is my code:
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/tippy.js#3/dist/tippy.all.min.js"></script>
<script>
tippy.setDefaults({
allowHTML: 1,
trigger: 'click',
hideOnClick : 'toggle'
})
function initAllValues() {
tippy('.enery', {
content: document.querySelector('#myTemplate')
})
}
</script>
</head>
<body onload="initAllValues()">
<span class="enery">Text</span>
<div id="myTemplate">
My HTML <strong style="color: pink;">tooltip</strong> content with an input field <input type="number" id="catch_value">
</div>
</body>
</html>

Solution as easier than thought:
One has to set the following option in tippy:
interactive: true option
Note: direct tippy support and discussions is available on their github, including answr to the present question: https://github.com/atomiks/tippyjs/issues/342#event-1935111700

Just do:
interactive: true
as in:
function initAllValues() {
tippy('.enery', {
content: document.querySelector('#myTemplate'),
interactive: true
})
}
or in:
tippy.setDefaults({
allowHTML: 1,
trigger: 'click',
hideOnClick : 'toggle',
interactive: true
})
Also have a look at Tippy's docs: https://atomiks.github.io/tippyjs/v6/all-props/#interactive and FAQ for problems using the interactive property: https://atomiks.github.io/tippyjs/v6/faq/#my-tooltip-appears-cut-off-or-is-not-showing-at-all

Related

Tail.select Datatables

I am trying to use tail.select from https://github.com/pytesNET/tail.select.
On the first page load its running well like what I want.
but when I call the row.add method from datatables, each dropdown not working anymore.
Hope somebody can help me to solve this issue.
Best Regards
Thankyou.
In the question's code, I assume that $('#master-row').html() is returning a fragment of HTML - possibly the contents of a <td>.
However, the DataTable row.add() function expects a JavaScript data structure - a JS array or object.
You can provide a variable containing "master row" data using something like this:
var masterRow = [
"",
"<select class=\"select2\"><option>first</option><option>second</option><option>third</option></select>",
"<textarea rows=\"3\" cols=\"20\"></textarea>"
];
It doesn't have to be hard-coded JS like this. It could also be sourced from an ajax call. But for this demo, I will use the above approach.
You can now use this "master row", containing three column values, as follows:
Here is the full HTML page for the demo:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Demo</title>
<script src="https://code.jquery.com/jquery-3.5.1.js"></script>
<script src="https://cdn.datatables.net/1.10.22/js/jquery.dataTables.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.datatables.net/1.10.22/css/jquery.dataTables.css">
<link rel="stylesheet" type="text/css" href="https://datatables.net/media/css/site-examples.css">
<!-- tail.select -->
<link type="text/css" rel="stylesheet" href="https://cdn.jsdelivr.net/npm/tail.select#latest/css/tail.select-default.css" />
<script src="https://cdn.jsdelivr.net/npm/tail.select#latest/js/tail.select.min.js"></script>
</head>
<body>
<div style="margin: 20px;">
<button type="button" class="btn-add">New Row!</button>
<br><br>
<table id="example" class="display dataTable cell-border" style="width:100%">
</table>
</div>
<script type="text/javascript">
var masterRow = [
"",
"<select class=\"select2\"><option>first</option><option>second</option><option>third</option></select>",
"<textarea rows=\"3\" cols=\"20\"></textarea>"
];
var dataSet = [];
dataSet.push(masterRow);
$(document).ready(function() {
var table = $('#example').DataTable( {
data: dataSet,
paging: false,
searching: false,
ordering: false,
columnDefs: [
{
targets: 0,
title: "Num",
render: function(data, type, row, meta) {
console.log(data);
return meta.row + 1;
}
},
{
targets: 1,
title: "Select Column"
},
{
targets: 2,
title: "Textarea Column"
}
]
}).on('draw', function() {
tail.select(".select2", {
search: true
});
});
table.draw();
$('.btn-add').click(function() {
table.row.add(masterRow).draw();
});
} );
</script>
</body>
</html>
Notes:
The dataSet variable takes the master row array and adds it into another outer array. This is needed so that we have a full 2-dimensional data structure for DataTables to use when it first loads the table. It is a 2D structure, but with only one (initial) row of data:
When we click on the "new row" button, it uses the masterRow variable as its source for the contents of the new row, resulting in this:
As you can see, the table has a new row, and the drop-downs are working as expected.
You can see the official documentation here for more details about the row.add() API call.

Why v-bind is one-way data binding while v-for can update data from children component in vue.js?

guys. I am reading the book of The Majesty Of Vue.js 2. I am confused with one example in the book.
My question is - why upvote button can modify data of Vue instance which displayed in pre tag while favorite button can not?
It is said that favorite is bound via v-bind directive, which is one way data binding means that children are not able to sync data with parent. But how did story get updated? Two way data binding like v-model?
Here is the code example:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello Vue</title>
</head>
<body>
<div v-cloak id="app">
<div class="container">
<h1>Let's hear some stories!</h1>
<ul class="list-group">
<story v-for="story in stories" :story="story" :favorite="favorite"></story>
</ul>
<pre>{{ $data }}</pre>
</div>
</div>
</body>
<template id="story-template">
<li class="list-group-item">
{{ story.writer }} said "{{ story.plot }}"
Story upvotes {{ story.upvotes }}.
<button v-show="!story.voted" #click="upvote" class="btn btn-default">Upvote</button>
<button v-show="!isFavorite" #click="setFavorite" class="btn btn-primary">Favorite</button>
</li>
</template>
<script src="../../vue.js"></script>
<script type="text/javascript">
Vue.component('story', {
template: "#story-template",
props: ['story', 'favorite'],
methods: {
upvote: function () {
this.story.upvotes += 1;
this.story.voted = true;
},
setFavorite: function () {
this.favorite = this.story;
}
},
computed: {
isFavorite: function () {
return this.story === this.favorite
}
}
});
window.app = new Vue({
el: '#app',
data: {
stories: [
{
plot: 'My horse is amazing.',
writer: 'Mr. Weebl',
upvotes: 28,
voted: false
},
{
plot: 'Narwhals invented Shish Kebab.',
writer: 'Mr. Weebl',
upvotes: 8,
voted: false
},
{
plot: 'The dark side of the Force is stronger.',
writer: 'Darth Vader',
upvotes: 49,
voted: false
},
{
plot: 'One does not simply walk into Mordor',
writer: 'Boromir',
upvotes: 74,
voted: false
}
],
favorite: {}
}
})
</script>
</html>
This has to do with how objects work in Javascript. When stored in a variable you sir a reference to that object. So when you pass it around, you're actually only passing the reference. Meaning that altering an object (not overwriting!), alters is on all places.
What happens in your example is that you modify the story object. You alter its keys but do not overwrite the object itself. Seeing the app has the same reference to the story object. The changes are shown.
In the case of the favorite however. You get passed the reference of the favorite object. But as soon as you click the favorite button. It swaps the variable to reference the story, but only locally. The app still holds the old reference. This is because you only pass the reference itself and not the parent object.
This is where state managers like Vuex come in to place.

dgrid (onDemandGrid) loads on first time button click, but error on second time button is clicked

Thanks to some previous help here, I got the Dojo dgrid to work; and even figured out how to tie it to data from my rest service.
Now I added an input box, a button, and all the logic happens on the button-click. But the second time I click the button, even with the same input value in the input field, I get an error.
ERROR:
TypeError: Cannot read property 'element' of undefined in StoreMixin.js:33
Including the picture so you can see my console.logs
I read this How To reset the OnDemandGrid, but is it necessary to check to see if grid exists and do different logic? Can't I just "new up" a new one each time?
CODE:
<div data-dojo-type="dijit/layout/ContentPane" data-dojo-props='title:"CustomersGrid"'>
<label for="lastnameStartsWith">Lastname Starts With:</label>
<input id="lastnameStartsWith" type="text" name="lastnameStartsWith" value="Wag"
data-dojo-type="dijit/form/TextBox"
data-dojo-props="trim:true, propercase:true" />
<br />
<br />
<button id="queryStudentsButton" data-dojo-type="dijit/form/Button"
data-dojo-type="dijit/form/Button"
data-dojo-props="iconClass:'dijitIconTask'">
<span>Query</span>
<script type='dojo/on' data-dojo-event='click'>
require([
'dstore/RequestMemory',
'dstore/Memory',
'dgrid/OnDemandGrid'
], function (RequestMemory, Memory, OnDemandGrid) {
var url = '../students/' + dojo.byId('lastnameStartsWith').value;
console.log("query students for dataGrid latsnameStartsWith:" + dojo.byId('lastnameStartsWith').value);
require(['dojo/request'], function(request){
request.get(url,
{headers: {"Content-Type": 'application/json',
"username": securityConfig.username,
"password": securityConfig.password}}
)
.then(function(response){
//console.log("string response=" + response);
var respJSON = JSON.parse(response);
var respDataForDGrid = respJSON.recordset;
console.log("got respJSON back, num rows= " + respDataForDGrid.length);
//================================================
// Create an instance of OnDemandGrid referencing the store
console.log("Debug1");
var grid2 = new OnDemandGrid({
collection: new Memory({ data: respDataForDGrid }),
columns: {
student_id: 'ID',
student_firstname: 'First Name',
student_lastname: 'Last Name',
student_city: 'City',
student_state: 'State',
student_zip: 'Zip'
}
}, 'grid2');
console.log("Debug2");
grid2.startup();
console.log("Debug3");
},
function(error){
console.log("Error=" + error);
//dom.byId('studentFeedback').value += response;
});
});
});
</script>
</button>
<h2>My demoGrid - From JSON RestService (Database)</h2>
<div id='grid2'></div>
</div>
Part 2 -
I tried mix of your code and code on this page:
How To reset the OnDemandGrid
if (grid2Registered){
console.log("reuse existing grid");
grid2Registered.set('collection', memStore);
// refresh: clear the grid and re-queries the store for data.
grid2Registered.refresh();
}
else{...
Doc here (https://github.com/SitePen/dgrid/blob/v0.4.3/doc/components/core-components/OnDemandList-and-OnDemandGrid.md) says:
Clears the grid and re-queries the store for data. If
keepScrollPosition is true on either the instance or the options
passed to refresh, an attempt will be made to preserve the current
scroll position. OnDemandList returns a promise from refresh, which
resolves when items in view finish rendering. The promise resolves
with the QueryResults that were rendered.
This one has been tough! Below a working example.
First I switched from declarative to programmatic for the onClick function: declarative scripts are parsed by dojo, and as a consequence you cannot examine them (set break points, etc.) under the debugger (at least I don't know how to do that). So it seems to me good practice to avoid them.
Then, indeed the bug is due to re-instantiating the dgrid with the same id, so that you do need a way to detect that the dgrid already exists. But there is a trick: for dgrids to be properly handled by the dijit system, they need to be mixed in with the dijitRegistry extension. See here for details.
Then you can use registry.byId('grid2') to detect that the dgrid already exists.
Also I had to skip the respDataForDgrid part and used directly respJSON instead (may be due to a difference with your server side(?) - I used a simple text file with a json array on the server side).
<!DOCTYPE HTML><html lang="en">
<head>
<meta charset="utf-8">
<title>Neal Walters stask overflow test</title>
<link rel="stylesheet"
href="dojo-release-1.12.2-src/dijit/themes/claro/claro.css"
media="screen">
<link rel="stylesheet"
href="dojo-release-1.12.2-src/dgrid/css/dgrid.css" media="screen">
</head>
<body class="claro">
<div data-dojo-type="dijit/layout/ContentPane"
data-dojo-props='title:"CustomersGrid"'>
<label for="lastnameStartsWith">Lastname Starts With:</label> <input
id="lastnameStartsWith" type="text" name="lastnameStartsWith"
value="Wag" data-dojo-type="dijit/form/TextBox"
data-dojo-props="trim:true, propercase:true" /> <br /> <br />
<button id="queryStudentsButton" data-dojo-type="dijit/form/Button"
data-dojo-props="iconClass:'dijitIconTask', onClick: myClick">Query</button>
<h2>My demoGrid - From JSON RestService (Database)</h2>
<div id='grid2'></div>
</div>
<script src="dojo-release-1.12.2-src/dojo/dojo.js"
data-dojo-config="async:true"></script>
<script type="text/javascript">
require(["dojo", "dojo/parser", "dojo/domReady!"],
function(dojo, parser){
parser.parse();
});
function myClick(){
var url = 'students/' + dojo.byId('lastnameStartsWith').value, securityConfig = {username: 'john', password: 'Doe'};
console.log("query students for dataGrid latsnameStartsWith:" + dojo.byId('lastnameStartsWith').value);
require(['dojo/_base/declare', 'dojo/request', "dijit/registry", "dstore/RequestMemory", "dstore/Memory", "dgrid/OnDemandGrid", "dgrid/extensions/DijitRegistry"], function(declare, request, registry, RequestMemory, Memory, OnDemandGrid, DijitRegistry){
request.get(url,{})
.then(function(response){
console.log("string response=" + response);
var respJSON = JSON.parse(response);
//var respDataForDGrid = respJSON.recordset;
//console.log("got respJSON back, num rows= " + respDataForDGrid.length);
//================================================
// Create an instance of OnDemandGrid referencing the store
console.log("Debug1");
var theGrid = registry.byId('grid2');
if (theGrid){
theGrid.set('collection', new Memory({data: respJSON}));
}else{
var grid2 = new (declare([OnDemandGrid, DijitRegistry]))({
collection: new Memory({ data: respJSON }),
columns: {
student_id: 'ID',
student_firstname: 'First Name',
student_lastname: 'Last Name',
student_city: 'City',
student_state: 'State',
student_zip: 'Zip'
}
}, 'grid2');
console.log("Debug2");
grid2.startup();
console.log("Debug3");
}
},
function(error){
console.log("Error=" + error);
//dom.byId('studentFeedback').value += response;
});
});
};
</script>
</body>
</html>

Vuejs 2 How to update v-model by component

I would like to create a component for i-check but I cannot get the v-model data during form submission.
I can do it via normal input element.
Below is an example. Thanks
<!DOCTYPE html><html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<script src="https://unpkg.com/vue"></script>
<title>JS Bin</title>
</head>
<body>
<div id=wrap>
<ichecker id="test" checked v-model="formData.checkbox"></ichecker>
<!--<input type=checkbox checked v-model="formData.checkbox" />-->
<button v-on:click.prevent=submit()>Submit</button>
</div>
</body>
</html>
Vue.component('ichecker', {
props: ['id', 'checked'],
model: {
prop: 'checked',
event: 'change'
},
template: "<input type='checkbox' :id='id' />",
mounted: () => {
// var $el = jQuery(`#${this.id}`);
// $el.iCheck({.....
}
});
new Vue ({
el: '#wrap',
data: {
formData : {
checkbox : ''
}
},
methods: {
submit: function() {
document.body.appendChild(document.createTextNode(this.formData.checkbox?'true ':'false '));
// form submission
}
}
});
https://jsbin.com/jugerigeto/edit?html,js,output
You are in a quite particular scenario where the <input> itself is the root element of your component. So you can't use v-model if you want to listen to the native event, cause it only exists on v-on. v-model is just a shorcut thought, and you can do it easily like this:
HTML:
<ichecker :checked="formData.checkbox"
#change.native="formData.checkbox = $event.target.checked">
</ichecker>
JS:
Vue.component('ichecker', {
prop: ['checked'],
template: '<input type="checkbox" :checked="checked" />'
});
https://jsbin.com/suvonolita/edit?html,js,output
You may also want to do it without the native event, if the input is not your root node. Or you may really want v-model. The way to implement v-model on a custom component is described there: https://v2.vuejs.org/v2/guide/components.html#Customizing-Component-v-model

Custom close button in datetimepicker form [duplicate]

$(function() {
$('input.month-mode').datetimepicker({
viewMode: 'months',
format: 'MM/YYYY',
showClose: true,
maxDate: current_month,
});
});
I want to add close text to it. by default it shows 'X', but I want to change it. Is it possible?
You can use icons option to define a custom css class for your icon and then you can write a css rule to customize close text as shown below:
$(function () {
var current_month = moment(); // just a sample value
$('#datetimepicker1').datetimepicker({
showClose: true,
viewMode: 'months',
format: 'MM/YYYY',
maxDate: current_month,
icons: {
close: 'closeText'
}
});
});
.closeText:before {
content: "Close";
}
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/css/bootstrap.css" rel="stylesheet"/>
<link href="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.7.14/css/bootstrap-datetimepicker.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/moment.js/2.12.0/moment.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.6/js/bootstrap.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/bootstrap-datetimepicker/4.7.14/js/bootstrap-datetimepicker.min.js"></script>
<div class='input-group date' id='datetimepicker1'>
<input type='text' class="form-control" />
<span class="input-group-addon">
<span class="glyphicon glyphicon-calendar"></span>
</span>
</div>
One way to do this is to use the icon classes to a add a new class and then use css to add some content. Something like:
$(function() {
$('input.month-mode').datetimepicker({
viewMode: 'months',
format: 'MM/YYYY',
showClose: true,
maxDate: current_month,
icons: {
close: 'textclass1'
}
});
});
Css:
.textclass1::before {
content: "Close";
}