I'm using the Tippy.js v6 library, and I'm struggling to work out how to change the content of any one of my instances using the delegate method. All the answers I've found on SO reference methods that are no longer available in v6.
I'm using v6 via the CDN.
Current delegate code
// Delegate tippy
const delegateInstances = tippy.delegate("#order__lines-table", {
target: "[data-tippy-content]"
});
If I console.log(delegateInstances) this I get an array with my items, but I can't seem to work out how to target 1 single instance inside here.
An example of what I'm doing is when you click a button its state toggles and I want the tippy content to update. I had done this like follows, but they just stack on top of each other, the old content doesn't get removed.
const viewBtnIcon = viewBtn.querySelector('i');
viewBtnIcon.dataset.tippyContent = `View ${data.name}`;
tippy(viewBtnIcon, {
content: `View ${data.name}`
});
Basically I need to know how to target a specific instance and update the content. I have to use the delegate method (from what I understand) as content is dynamically added to the page.
The following code is how I got it to work based on issue #767 and issue #774 on the original GitHub repo
const viewBtnIcon = viewBtn.querySelector('i');
if (viewBtnIcon._tippy) {
viewBtnIcon._tippy.setContent(`View ${data.name}`);
} else {
viewBtnIcon.dataset.tippyContent = `View ${data.name}`;
}
I have a similar use and this is how I change the tip content dynamically:
the content property will be replaced with the content you set onShown, this will work even with async calls.
delegate("#tippyRoot", {
target: "[data-tippy-content]",
content: 'loading',
animation: "scale",
theme: "light",
trigger:'hover',
allowHTML: true,
onShown(instance) {
let cont = instance.reference.dataset.tippyContent;
//do something...
instance.setContent(cont);
},
});
Related
We are currently using quilljs for a project. When we try to add html through the dangerouslyPasteHTML API from the Clipboard module, the custom attributes from the paragraphs are stripped.
For example:
On applying the following code :
quill.clipboard.dangerouslyPasteHTML("<p data-id='1'>Hello</p>");
The output obtained is
<p>Hello</p>
How do you retain the attribute 'data-id' in the output?
UPDATE 1:
I have managed to retain the custom attribute 'data-id' using the following code:
var Parchment = Quill.import('parchment');
var dataId = new Parchment.Attributor.Attribute('data-id', 'data-id', {
scope: Parchment.Scope.BLOCK
});
Quill.register(dataId);
However, on creating a new line (hitting the enter key), the same data-id is appearing in the new paragraph as well. How do I ensure that the new paragraph either has a custom data-id or does not contain the 'data-id' attribute?
I am pretty late to answer this, but for anyone encountering this issue, I have fixed it in the following way:
import Quill from 'quill';
const Parchment = Quill.import('parchment');
const IDAttribute = new Parchment.Attributor.Attribute('id-attribute', 'id', {
scope: Parchment.Scope.BLOCK,
});
Quill.register(
{
'attributors/attribute/id': IDAttribute,
},
true
);
Quill.register(
{
'formats/id': IDAttribute,
},
true
);
const Block = Quill.import('blots/block');
class BlockBlot extends Block {
constructor(domNode) {
super(domNode);
domNode.setAttribute('id', '');
this.cache = {};
}
}
BlockBlot.blotName = 'block';
export default BlockBlot;
So basically we want to make a custom Blot extending from the Block blot available and use it for the Block format execution. In the constructor we can do whatever we want to do with the attribute. In my case I am removing the id attribute which was being added to new block.
I would recommend adding event handling in the textChanged method. You could check the delta and see if the 'insert' also contains an 'attributes' field that would cause it to be modified. If that happens, you can trigger an updateContents that retains through the current selection index. Then delete the length of the insert, and reinsert without the attributes.
I'm using layzr.js in my backbone.js project, in order to do a lazy loading image.
Here I put it in my backbone view :
render: function(){
var _item = _.template(ItemTem);
this.$el.html(_item(this.model.toJSON()));
$(document).ready(function() {
var layzr = new Layzrr({
selector: '[data-layzr]',
attr: 'data-layzr',
retinaAttr: 'data-layzr-retina',
bgAttr: 'data-layzr-bg',
threshold: 0,
callback: null
});
});
}
});
Every image works fine except the last image, it is not loaded. I have no idea what's wrong with it or did I do any thing wrong.
I attempted to find an answer to my question with the search engine but i was unable to.
First off remove $(document).ready(function() { from your view render method.
You should have DOM ready before view is rendered.
Remove that lazyloader logic altogether form render. And move it to it's parent.
You need to make sure that your view is rendered in DOM before you bind anything to it.
So I would to it this way:
var yerrView = new YourView();
$('body').append(yerrView.render().el);
var layzr = new Layzrr({
selector: '[data-layzr]',
attr: 'data-layzr',
retinaAttr: 'data-layzr-retina',
bgAttr: 'data-layzr-bg',
threshold: 0,
callback: null
});
I would write custom lazy loader for backbone if I were you.
I'm using Mutation Summary library to observe when a particular type of elements have been added and then append my html element to each of them:
var observer = new MutationSummary({
callback: theNextPageLoaded,
queries: [{
element: "li.sweet"
}]
});
function theNextPageLoaded(summaries) {
var sc = summaries[0],
sc_length = sc.added.length,
btn = $('<button>', {
class: 'my_btn',
text: 'Please work!'
});
sc.added.forEach(function(newEl) {
newEl.appendChild(btn);
console.log(typeof(newEl)); //newEl's type is 'object'
});
}
Code above is not working. I'm not sure I can even use appendChild on an object. Any help would be appreciated!
Your problem is mixing together "bare" DOM elements from Mutation Summary response and jQuery elements. Pure DOM appendChild does not understand your jQuery-wrapped btn.
So, you need to make them both to be the same type:
$(newEl).append(btn); // jQuery
newEl.appendChild(btn.get(0)); // pure DOM
Either works, but the first one is probably more idiomatic.
I'm trying to register my onClick listener to dijit Button placed as in-cell widget withing GridX. I've done the following, basing on example test_grid_cellWidget:
{ field: "save", name:"Save",
widgetsInCell: true,
navigable: true,
decorator: function(){
//Generate cell widget template string
return '<button data-dojo-type="dijit.form.Button" data-dojo-attach-point="btn">Save</button>'
},
setCellValue: function(data){
//"this" is the cell widget
this.btn.set("label", "Speichern")
this.btn.connect("onClick", function(){
alert('clicked')
})
}
},
setCellValue is executed successfully, and the label is changed. However, the onClick listener is not registered and is not called, when I click on button. When I use the syntax data-dojo-props="onClick:function" it works, but it requires declaring listener function as global, which is something I'd like to avoid.
Anyway, I have the Button object, and I'm executing the code found in dijit documents, so it should be working. But why nothing is registered in that context?
I've found the answer in GridX wiki: https://github.com/oria/gridx/wiki/How-to-show-widgets-in-gridx-cells%3F
You need to use the field cellWidget.btn._cnnt:
setCellValue: function(gridData, storeData, cellWidget){
this.btn.set("label", "Speichern")
if(cellWidget.btn._cnnt){
// Remove previously connected events to avoid memory leak.
cellWidget.btn._cnnt.remove();
}
cellWidget.btn._cnnt = dojo.connect(cellWidget.btn, 'onClick', lang.hitch(cellWidget.cell, function(){
rowSaveClick(this.row)
}));
},
I don't know what dojo version you use, but as you use data-dojo-type, I suppose it's 1.7+.
First, I would recommend to drop the dot notation of module names and start using the AMD mid syntax instead (i.e.: drop "dijit.form.Button" for "dijit/form/Button", as the dot notation will be dropped in dojo 2.0).
Then, the recommended way of connecting events to widgets is to :
either define the event as a function (like widget.onClick = function(evt){...})
or use the "on" method of the widget (like widget.on("click", function(evt){...}))
I prefer to use the second form, as it's more consistent with dojo/on. It consists of using the event name without the "on", and put everything in lowercase. For example, if your widget had an extension point named "onMouseRightClick", you could use it as widget.on("mouserightclick", ...)
Your example would then become :
{ field: "save", name:"Save",
widgetsInCell: true,
navigable: true,
decorator: function(){
//Generate cell widget template string
return '<button data-dojo-type="dijit/form/Button" data-dojo-attach-point="btn">Save</button>'
},
setCellValue: function(data){
//"this" is the cell widget
this.btn.set("label", "Speichern")
this.btn.on("click", function(){
alert('clicked')
});
}
},
Note : untested code. I'm just guessing what the problem might be. Let me know if there is still an issue...
I've found that using getCellWidgetConnects works quite well (see docs).
But the docs aren't exactly clear, so it wasn't working for me at first. If you are connecting to a DomNode, the pass 'click' as the event in the connections array. If you are connecting to a Dijit widget, then pass 'onClick'.
Ember.LinkView, the the view class behind the handlebars {{linkTo}} helper is now public in Ember 1.0 RC2. I want to extend it so I can create a custom view without having an extra nested tag for linkTo.
For example:
App.MyLinkView = Ember.LinkView.extend({
namedRoute: 'another'
});
then
{{#view App.MyLinkView}}LinkView to another route{{/view}}
Looked through the source a bit without much luck, as it constantly throws an error.
Here's a jsfiddle with the standard {{linkTo}} working, and the LinkView attempt commented out so it doesn't throw an error.
http://jsfiddle.net/HgmEy/1/
Edit:
Here is a more realistic example of why you would want to do this:
http://jsfiddle.net/HgmEy/3/
The desired functionality is working here using a regular view, however using a LinkView would be preferred to avoid the extra dom element.
LinkView is intended to be created via a helper, which passes (and provides default values for) some options.
Your error occurs when trying to determine whether your custom class is active or not. You'll need to do one of the following
pass or supply the expected default options when using your App.MyLinkView
override the active function and implement what you need
just pass options to {{linkTo}} for the behavior you want
reopen Ember.LinkView to provide the app-wide behavior you'd want
I needed to do this to override Ember.LinkView's call to transitionTo in order to come up with a solution for jQuery animations between transitions. It seems to me that there are a couple of viable ways to override LinkView. The second one I succeeded with is Trek's last option, and is simpler. This is method #2:
Method #2
{{#linkTo 'items' this eventName="myEvent"}} Link to {{title}} {{/linkTo}}
Now rewrite the app-wide LinkView:
Ember.LinkView.reopen({
// this handler is still called on click, but
// if we specify eventName in our template,
// we can call that handler only when we need to,
// or not at all
click: function (e) {
var evtName = this.get('eventName');
// transitionTo was already invoked by
// this._invoke() if evtName was `click`
if (evtName === 'click') return;
e.preventDefault();
// do some stuff here
var args = [].slice.call(arguments);
this.trigger.apply(this, [evtName].concat(args));
}
});
Method #1
The first method I came up with was to extend Ember.LinkView and create a custom Handlebars helper. The Ember source was really handy here for reading, but I had to override a private method, so I don't think this is really ideal. Here's the implementation. Keep in mind I was trying to control when the View triggered a transitionTo:
{{#appLinkTo 'items' this}} Link to {{title}} {{/appLinkTo}}
Now code it up!
App.LinkView = Ember.LinkView.extend({
// always called after this.invoke(),
// which calls transitionTo
click: function (e) {
e.preventDefault();
},
// already bound to the click event by this.init().
// our click handler above always gets called after this one
_invoke: function (event) {
// we need to simulate the old _invoke if we
// want to override its call to transitionTo
//
// https://github.com/emberjs/ember.js/blob/v1.0.0/packages/ember-routing/lib/helpers/link_to.js#L297
var isSimpleClick = Ember.ViewUtils.isSimpleClick;
if (!isSimpleClick(event)) { return true; }
event.preventDefault();
if (this.bubbles === false) { event.stopPropagation(); }
if (this.get('_isDisabled')) { return false; }
if (this.get('loading')) {
Ember.Logger.warn("This link-to is in an inactive loading state because at least one of its parameters presently has a null/undefined value, or the provided route name is invalid.");
return false;
}
// now we can start messing around
var routeArgs = this.get('routeArgs');
// routeArgs seems to have format ['routeName', models for dynamic segments]
this.set('routeArgs', ['group', routeArgs[1]]);
// if we use:
this.get('controller').send('someAction', routeArgs);
// the controller can do in its `someAction` handler:
// `this.transitionToRoute.apply(this, routeArgs);`
}
});
// besides the naming, this is verbatim from the end of:
// https://github.com/emberjs/ember.js/blob/v1.0.0/packages/ember-routing/lib/helpers/link_to.js
Ember.Handlebars.registerHelper('app-link-to', function(name) {
var options = [].slice.call(arguments, -1)[0],
params = [].slice.call(arguments, 0, -1),
hash = options.hash;
hash.disabledBinding = hash.disabledWhen;
hash.parameters = {
context: this,
options: options,
params: params
};
return Ember.Handlebars.helpers.view.call(this, App.LinkView, options);
});
Ember.Handlebars.registerHelper('appLinkTo', Ember.Handlebars.helpers['app-link-to']);
Method #3
If you want the best of both, you could combine both methods and extend Ember.LinkView, create a custom Handlebars helper, and use custom event names to signify which actions you want to take. That way, overriding Ember.LinkView, and overwriting _invoke aren't necessary.
Good luck!