how to execute local method from Ext.Template and Ext.apply methods - javascript

I want to execute a local method in Ext.Template context.
The method should be a member in the class.
I tried the following code and it doesn't work.
Someone know of can I pass the function member to onClick event?
requires: ['Ext.XTemplate'],
alias : 'widget.countlinkcolumn',
func: 'this.handleFilter'
renderer: function(val,metaData,rec,b,c,d,f){
var categoryId = 3;
var colTemplate = new Ext.Template(
'<div class="drill_down_link grid_cell_link" style="cursor: pointer; float:right" onclick="{on_click}({categoryId})">{text}</div>' +
'</div>');
var tpl = colTemplate.apply({
text: text,
categoryId: categoryId,
on_click: this.func,
});
return tpl;
},
handleFilter: function (categoryId) {
console.log(categoryId);
},
});

Never found an simple solution to this problem... The XTemplate can't directly call ExtJS code from it (it's actually already rendered in the DOM)...
The workaround we found is to render the XTemplate in a View (But you can do it with apply()) then listening to the itemClick event.
In the listener we get the DOM element and we can get some additional data from an attribute (eg: data-categoryId):
xtype: 'view',
listeners: {
itemClick: 'onItemClick',
}
// Additional attribute (data-categoryId) that store the categoryId
tpl: '<div data-categoryId="{categoryId}" class="drill_down_link">{text}</div>'
Then in the listener we can use this additional attribute after we checked that the correct button was clicked (by his class name but you can use other attribute)
onItemClick: function(dataView, record, item, index, e, removeAll){
var me = this,
target = e && e.target,
targetClass = target && target.getAttribute("class");
//Clicked on link (identified by his class name)
var isLink = targetClass && targetClass.indexOf("drill_down_link") >= 0;
if(isLink){
// Get the attribute value we setted in the XTemplate
var categoryId = target.getAttribute('data-categoryId');
}
}

Related

Javascript variable scope when adding function to array

I am using TinyMCE 4 and trying to build a dynamic menu. In order to do this I am building an array of menu items which includes an onclick function. The menu displays, but the onclick function does not work because when building the array, the value I need to pass to the function is out of scope - I believe.
var MenuItems = [{"Id":"1","Name":"MenuItem 1"},{"Id":"2","Name":"MenuItem 2"}];
var Menu = [];
for (var i=0;i<MenuItems.length;i++)
{
Menu.push({
text: MenuItems[i].Name,
onclick: function(){
alert(MenuItems[i].Id);
}
});
}
In the onclick declaration, MenuItems[i].Id is not in scope - I believe.
How can I pass the values to the onclick function.
I am then passing the array to the TinyMCE plugin, but I don't believe this is a problem with TinyMCE, but posting this part in case there is a better way.
tinymce.PluginManager.add('myplugin', function(editor, url) {
editor.addButton('menu', {
text: 'MyMenu',
type: 'menubutton',
icon: false,
menu: Menu
});
});
MenuItems[] won't be available when the callback for myplugin would run.
This would also mean, that once, onclick of any menuItem is called, it would try accessing MenuItems[].
To fix this, once way could be to change the implementation like:
var MenuItems = [{"Id":"1","Name":"MenuItem 1"},{"Id":"2","Name":"MenuItem 2"}];
var Menu = [];
for (var i=0;i<MenuItems.length;i++)
{
const id = MenuItems[i].Id;
Menu.push({
text: MenuItems[i].Name,
onclick: function(){
alert(id);
}
});
}

attach onclick/ng-click event to element in grid databound event

I have a TypeCtrl ES6 class angular controller which uses a kendo datagrid directive and has template for grid config options , In the template for the grid, i need to call a method from the TypeCtrl class. I need to attach an onclick or ng-click event to the span within the row of the template. However teh function that needs to be triggered on click belongs to the TypeCtrl class. How can i get the context of TypeCtrl within the databound event of teh kendo grid. I see that "this" points to the kendo grid here,
Here is what i have, please let me know as to how i can access teh controller method within the databound event
//Grid options defined in Class TypeCTrl along with openSub method
class TypeCtrl{
constructor() {}
$onInit() {
this.gridOptions = {
name: 'test',
dataBound: function(e) {
//Find the span and on click , attach the typectrl controller's opensub method
let grid = this
let item = grid.tbody.find('#testClick');
let value = item.innerHTML;
item.on('click', this.openSub(value);
}
columns: [{
field: 'subscriptionName',
hidden: true,
groupHeaderTemplate: function(dataItem) {
let temp;
let sname = dataItem.value;
if (sname) {
temp = '<span id="testClick">' + sname + '</span>';
}
return temp;
}.bind(this)
}, {
field: 'name',//Todo: show icons
title: 'name'
}, {
field: 'version',
title: 'version'
}]
}
}
openSub(name) {
alert('thisis a box');
}
}
TypeCtrl.$inject = ['$scope'];
angular.module('core').controller('TypeCtrl', TypeCtrl);
export default TypeCtrl;
I see that when i click on the span tag, the context of this is lost and opensub method is not called. I ned to get to the opensub method when clicked on the row template , can i do this in the dataBound function??
or any other way s?
The common approach is to build AngularJS app with components. If you create a component that contains your grid, then you'll be able to call openSub() method from the template: ng-click="$ctrl.openSub()". In this case, this in your method will point to the TypeCtrl.

JointJS element containing HTML button onclick show form

I am showing a form on addDetail buttton inside this element. How can I bind my data to this cell and send it to the server using the toJSon() method?
// Create a custom view for that element that displays an HTML div above it.
// -------------------------------------------------------------------------
joint.shapes.html.ElementView = joint.dia.ElementView.extend({
template: [
'<div class="html-element">',
'<button class="delete">x</button>',
'<label></label>',
'<span></span>', '<br/>',
'<input type="text" name="name" placeholder="name"/>',
'<button class="addDetail">+</button>',
'</div>'
].join(''),
initialize: function () {
_.bindAll(this, 'updateBox');
joint.dia.ElementView.prototype.initialize.apply(this, arguments);
this.$box = $(_.template(this.template)());
// Prevent paper from handling pointerdown.
this.$box.find('input').on('mousedown click', function (evt) {
evt.stopPropagation();
});
// This is an example of reacting on the input change and storing the input data in the cell model.
this.$box.find('input').on('change', _.bind(function (evt) {
alert($(evt.target).val());
this.model.set('input', $(evt.target).val());
}, this));
this.$box.find('.delete').on('click', _.bind(this.model.remove, this.model));
this.$box.find('.addDetail').on('click', _.bind(function (evt) {
addActionDetail();
})
);
// Update the box position whenever the underlying model changes.
this.model.on('change', this.updateBox, this);
// Remove the box when the model gets removed from the graph.
this.model.on('remove', this.removeBox, this);
this.updateBox();
},
render: function () {
joint.dia.ElementView.prototype.render.apply(this, arguments);
this.paper.$el.prepend(this.$box);
this.updateBox();
return this;
},
updateBox: function () {
// Set the position and dimension of the box so that it covers the JointJS element.
var bbox = this.model.getBBox();
// Example of updating the HTML with a data stored in the cell model.
this.$box.find('label').text(this.model.get('label'));
this.$box.find('span').text(this.model.get('select'));
this.$box.css({
width: bbox.width,
height: bbox.height,
left: bbox.x,
top: bbox.y,
transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)'
});
},
removeBox: function (evt) {
this.$box.remove();
}
});
}
In order to save some data on your element you must follow this steps:
Add some elementData propery to the shape model.
Each time the user click on addDetail inside your element you must have the element id, extract the elementData out of it, and then to render the form (you can achieve this by adding custom event listener to your paper)
When clicking the submit form, add add some custom trigger event.
Listen to that triggered event on your graph and try look for the specific cell by the ModelId and update it.
Here is the basic idea example:
1.your shape model:
joint.shapes.myShapes = joint.shapes.myShapes || {};
joint.shapes.myShapes.Element = joint.shapes.basic.Generic.extend({
//basically the defaults function doesn't needed, because the set function adds that automatically.
defaults: _.defaultsDeep({
elementData: null,
}, joint.shapes.basic.Generic.prototype.defaults),
getElementData: function () {
return this.get("elementData");
},
setElementData: function (elementData) {
this.set("elementData", elementData);
},
});
2.On your paper init, add your custom event listener function,
notice that you must have the ModelId to be remembered:
paper.on('addDetail:click', function (cell) {
var elementData = cell.model.getElementData();
elementData.ModelId = cell.model.id;
formRender(elementData);
});
3.trigger some custom event on your submit and the object to be updated within the element model:
function formSubmit() {
graph.trigger('custom:update', newElementData);
}
4.Add some custom event listener to your graph, add call the setElementData by the ModelId:
graph.on('custom:update', function (elementData) {
var cell = graph.getCell(elementData.ModelId);
cell.setElementData(elementData);
}, this);
Now you can send it to the server using the toJSon() method.

How to access caller element inside callback function

I have a jquery-ui button test-button that has a data attribute.
That button calls a custom widget customWidget that has a callback function fnSaveCallback.
$(".test-button").button({
icons: {
primary: 'icon-test icon-mixed icon-custom'
},
text: false
}).customWidget({
id: "custom-widget",
title: "My custom widget",
fnSaveCallback: function() {
// Need to get the data-test attribute from the "test-button"
}
});
I'm having problems trying to access the the test-button in order to get the value of the data-attribute from the callback function.
Any idea how can i do that? Thanks in advance!
I've found an easy way to handle this adding a class on the click event.
$(".test-button").button({
icons: {
primary: 'icon-test icon-mixed icon-custom'
},
text: false
}).click(function() {
// remove opener class from other test-buttons
$(.test-button.opener).removeClass("opener");
// add opener class to the clicked button
$(this).addClass("opener");
}.customWidget({
id: "custom-widget",
title: "My custom widget",
fnSaveCallback: function() {
// Get the data-test attribute from the "test-button"
$(".test-button.opener").data("test");
}
});
You need to have a reference of the element somewhere.
const test_button = document.getElementById('test-button');
and then in fvSaveCallback:
fnSaveCallback: function() {
// Need to get the data-test attribute from the "test-button"
console.log(test_button.dataset.test);
}
EDIT: After your edit, as far as I understand you are trying to apply that method to all .test-button buttons.
You should only need to get a list of nodes, and iterate through it :)
const test_buttons = document.getElementsByClassName('test-button')
;
for (let i = 0; i < test_buttons.length; i++)
{ const button = test_buttons[i]; //This is the button
// Do with 'button' whatever you want here.
console.log(button.dataset.some_data);
}

Bind function to the onClick on other scope

I'm trying to bind a function to the anchor onclick attribute. I'm not using the traditional jQuery's bind/live/on/whatever because I have some other scripts stopping the events propagation (it sucks, I know).
To bind the function to the onclick attribute I'm passing a JSON object to a module like this:
function foo() {
alert('foo')
}
$('document').ready(function() {
var options = {
opt1: 'fooID',
opt2: 'barID',
json: mightyJSON,
actions: [
{ url: 'contact/_id_/edit', text: "Edit", iconPath: 'edit.png' },
{ url: '#', onClick: foo, text: "Delete", iconPath: 'delete.png' }
]
};
var trolol = myModule.configure(options);
});
As you can see the function named "foo" is passed via the onClick property of the JSON. The function is defined above the object.
In myModule I'm creating the anchor tag like this:
var buildLinks = function(objectID)
{
var linksNbr = actions.length;
var link, cssClass;
for (var i = 0; i < linksNbr; i++)
{
// Adding the object ID to the URL
link = actions[i].url.replace('_id_', objectID);
cssClass = actions[i].cssClass || '';
var $link = $(document.createElement('a')).attr('onClick', actions[i].onClick)
.attr('href', link)
.attr('title', actions[i].text)
.addClass(cssClass)
.text('foo');
}
return $link.html();
};
The thing is, as you can expect 'foo' is executed when the script is parsed and only there. The onclick doesn't even work after.
I can pass it like this onClick: 'foo()'. The onclick works but it's also executed at parsing and it's, in my opinion, very ugly.
I'd like to still be able to pass it like this onClick: foo but working correctly (i.e. not being executed at loading but only when clicking.
It has to work with jQuery 1.4.4 unfortunately.
I would do it like this:
var $link = $('<a></a>',{
href : link,
title : actions[i].text,
'class' : cssClass,
text : 'foo',
click : actions[i].onclick
})
return $link;
Then use one of these (1,2) functions to insert the node, which is the html with events.
for the propagation issue i would do something like this:
html <a href="#no" ....>text</a>
js $('a[href="#no"]').live('click',function(){ return false; });
This way whenever the href is pointing to #no the event is eventually propagated
if at all possible, return the element, and not its .html()
having done that, don't use .attr('onclick', ...) when you've already got a function reference, use .prop, or even just element.onclick = ...
e.g.
$link = $('<a>', {
href: link,
title: actions[i].text,
'class': cssClass,
text: 'foo'
}).prop('onclick', actions[i].onClick);
Here is a fiddle snippet. If this approach is fine, you could as below set onclick on jquery's raw element, like this:
$link[0].onclick = options.actions[i].onClick;

Categories