I am trying to trigger a custom function inside of my columnDef cell template as follows:
export class GridComponent {
constructor() {}
this.gridOptions = {
// grid options defined here
columnDef.cellTemplate = '<bss-cell cellval="{{row.entity[col.name]}}"></bss-cell>';
}
private cellClicked () {
// need to get the click event here but can't
console.log('got here');
}
}
This column definition holds the data in my grid. Bss Cell is a custom angular component I made which looks like this:
//BSS CELL CONTROLLER CODE FOR THE COLUMN DEF CELL TEMPLATE
import * as angular from 'angular';
import '../../../../modules/bss/bss.component';
export class TreeCellComponent {
constructor() {
}
private cellClicked () {
// click event does come here if I call $ctrl.cellClicked() from my template but this isn't connected to the grid
}
}
angular.module('app.modules.uigridtemplates.bss-cell', ['app.modules.bss'])
.component('bssCell', {
bindings: {
cellval: '#'
},
controller: TreeCellComponent,
template: require('./bss-cell.html')
});
// BSS CELL DIRECTIVE TEMPLATE
<div ng-click="grid.AppScope.cellClicked()" align="right" class="ui-grid-cell-contents-data-grid" title="
{{$ctrl.cellval}}">
<span>{{$ctrl.cellval}}</span>
</div>
How can I get that click to take place so that it runs to the "cellClicked" function inside of my GridComponent, which would then allow me to affect the grid the way I would like.
this.cellTemplates = ['uiGridTreeCellTemplate.html', 'uiGridTreeColumnHeaderTemplate.html'];
this.gridOptions = {
appScopeProvider: this
}
Inside your gridOptions add this:
appScopeProvider: {
cellClicked: this.cellClicked
}
In this way in you grid.appScope you will find the cellClicked function available.
If you have selectable rows, which perform an action when you select one of your rows, I suggest to pass the $event to your grid.appScope.cellClicked() function, then in your appScopeProvider stop the click event, something like this:
ng-click="grid.appScope.cellClicked($event)"
and then
appScopeProvider: {
cellClicked: (event) => {
this.cellClicked();
event.preventDefault();
event.stopPropagation();
}
}
Related
I'd like to mark each field wrapping container with custom css class when field is focused and remove that class when field is blured. So I would like to attach focus/blur event methods to every form field component I add to any form.
in Ext 4 I did it like this:
Ext.ComponentManager.all.on('add', function(map, key, item) {
// Check if item is a Window and do whatever
if (item instanceof Ext.form.field.Base) {
item.on('focus', function(theField) {
var parentDom = null; //theField.bodyEl.findParent('.x-form-fieldcontainer');
if (!parentDom) {
parentDom = theField.bodyEl.findParent('.x-field');
}
if (parentDom) {
var parentEl = Ext.get(parentDom);
parentEl.addCls('focused-field');
}
}, item);
item.on('blur', function(theField) {
var parentDom = null; //theField.bodyEl.findParent('.x-form-fieldcontainer');
if (!parentDom) {
parentDom = theField.bodyEl.findParent('.x-field');
}
if (parentDom) {
var parentEl = Ext.get(parentDom);
parentEl.removeCls('focused-field');
}
}, item);
}
});
I'm not sure how to do it in ExtJS 6
Any help appreciated
Regards
Armando
You don`t need it, ExtJs has already '.x-field-focus' css class which is added to wrapper element on focus, so you can try to add your styles to the existing class. You can also look at the $form-field-focus-* theme variables..
Anyway, if you want to add this functionality, you can override the 'Ext.form.field.Base' class which is the parent of all the form fields.
Something like this:
Ext.define('overrides.form.field.Base', {
override: 'Ext.form.field.Base',
customCssOnFocus: 'focused-field',
initEvents: function() {
this.callParent(arguments);
this.on('focus', this.addCustomCssOnFocus, this);
this.on('blur', this.removeCustomCssOnBlur, this);
},
addCustomCssOnFocus: function() {
Ext.get(this.getEl().findParent('.x-field')).addCls(this.customCssOnFocus);
},
removeCustomCssOnBlur: function() {
Ext.get(this.getEl().findParent('.x-field')).removeCls(this.customCssOnFocus);
}
});
I would like to know how to use $formatters and $parsers with angular 1.5 components. Can someone post an example.
Or is there something similar that I can use.
The following is an example of a component called example. This takes in a object that contains firstName and secondName. It then displays a combination of the firstName and secondName. If the object changes from the outside the formatter will fire followed by the render. If you want to trigger a change from the inside, you need to call this.ngModel.$setViewValue(newObject) and this would trigger the parser.
class example {
/*#ngInject*/
constructor() {}
// In the post link we need to add our formatter, parser and render to the ngmodel.
$postLink() {
this.ngModel.$formatters.push(this.$formatter.bind(this));
this.ngModel.$parsers.push(this.$parser.bind(this));
this.ngModel.$render = this.$render.bind(this);
}
// The formatter is used to intercept the model value coming in to the controller
$formatter(modelValue) {
const user = {
name: `${modelValue.firstName} ${modelValue.secondName}`
};
return user;
}
// The parser is used to intercept the view value before it is returned to the original source
// In this case we want to turn it back to it's original structure what ever that may be.
$parser(viewValue) {
// We know from out formatter that our view value will be an object with a name field
const namesParts = viewValue.name.split(' ');
const normalisedUser = {
firstName: namesParts[0],
secondName: namesParts[1],
};
return normalisedUser;
}
// This will fire when ever the model changes. This fires after the formatter.
$render() {
this.displayName = this.ngModel.$viewValue.name;
}
}
class ExampleComponent
{
bindings = {};
controller = Example;
require = {
ngModel: 'ngModel',
};
}
component('example', new ExampleComponent());
// Template for example component
<span>
{{ $ctrl.displayName }}
</span>
// Using the above component somewhere
<example ng-model="userModel"></example>
I have a Polymer 1.0 iron-pages element containing two custom elements:
<iron-pages selected="...">
<my-page>A</my-page>
<my-page>B</my-page>
</iron-pages>
I would like to take some action, like fetching ajax content, in my-page component, when the page becomes selected. How can I do this?
I came up with some ideas:
create a third component containing the iron-pages and wiring the events
<dom-module id="my-controller">
<template>
<iron-pages selected="..." on-selected-changed="onPageChanged">
...
<script>Polymer({...
...
onPageChanged:function(){
var page = ...;
page.selected = true;
}
and
<dom-module id="my-page">
...
onSelected:function(){
// fetch data
}
seems being rather much of an overhead to me, is this really necessary?
use <iron-pages selectedAttribute="..." ...>
but I could not find a way to detect the attribute change in <my-page>
Are there common patterns to solve this?
My solution was similar to your option A, but using events instead of method calls - its a more correct approach, and I'm actually baffled why Polymer's ironSelectableBehavior didn't implement it directly:
<iron-pages id="pages" ...>
<my-first-page></my-first-page>
<my-second-page></my-second-page>
</iron-pages>
...
<script>
Polymer({
is: 'my-app',
listeners: {
'pages.iron-select': 'pageSelected',
'pages.iron-deselect': 'pageDeselected'
},
pageSelected: function(e) { e.detail.item.fire('iron-select'); },
pageDeselected: function(e) { e.detail.item.fire('iron-deselect'); })
});
</script>
Then, in your element, listen for these events:
Polymer({
is: 'my-custom-element',
listeners: {
'iron-select': '_refreshData'
},
_refreshData: function(e) {
// load some data
}
});
Option B should also work - you probably need to set up the correct property and put an observer on it. In your component that contains iron-pages set up the attribute using the hyphenated form:
<iron-pages selected-attribute="activated" ...>
<my-first-page></my-first-page>
<my-second-page></my-second-page>
</iron-pages>
Then in your custom component set up the property and the observer:
Polymer({
is: 'my-first-page',
properties: {
activated: {
type: Boolean,
observer: '_activationChanged'
}
},
_activationChanged: function(newval, oldval) {
if (newval) // == true
console.log("just activated");
}
});
<iron-pages selected-attribute="visible"></iron-pages>
class MyClass extends PolymerElement {
get activePage() {
return this.shadowRoot.querySelector('iron-pages > *[visible]');
}
}
(sorry for the zombie thread, but came looking for this).
If you add a region to a layout view using the regions hash like so:
regions: {
compositeRegion: '#ui.compositeViewDiv',
modalRegion:{
regionClass:modal,
selector:'.modalRegion'
}
}
The views that you show in those regions can call triggerMethod and trigger an event on their parent view.
If instead I build my regions (for instance, in a composite view or even an item view) like so:
App.addRegions({
compositeRegion: '#ui.compositeViewDiv',
modalRegion:{
regionClass:modal,
selector:'.modalRegion'
}
Nothing happens when you call triggerMethod. It does not seem to have the _parent attribute defined on the region.
If I manually set _parent to any view, it will trigger a method on the next highest up layout view.
For example, I have a Layout view "A" with a composite view "B", and that composite view "B" has an item view "C". If I create a region using App.addRegions code above in the item view "C", I can then set the _parent and show a view like so:
App.modalRegion._parent = this;
App.modalRegion.show(new someView());
The Layout view "A" childEvent is triggered, not the item view "C", nor the Composite view "B".
If I manually call
this.triggerMethod('sameeventname');
on the item view "C", it WILL trigger the composite view "B"'s childEvent.
Any ideas? I need to be able to use my modal region (takes any marionette view and turns it into a jQuery-UI modal) from anywhere. It works great when you use it with the layout view region hash. But since there is no region hash in a composite or item view, it works but will not communicate with its parent view.
I would recommend having a look at James Kyle's Marionette Wires, in particular the way services are used to display global components such as modal and flashes in his example.
The basic architecture is an application, with a LayoutView containing a region for each component. This is rendered on initialize and the component is passed the region from the app.
For rendering a view in a modal something like the following should work:
//layout-view.js
import { LayoutView } from 'backbone.marionette';
export const BaseLayout = LayoutView.extend({
regions: {
modal: '.modal',
...
}
});
//app.js
import { Application } from 'backbone.marionette';
import { BaseLayout } from './layout-view';
export const App = Application.extend({
initialize(options = {}) {
this.layout = new Layout({
el: options.el
});
this.layout.render();
}
});
//modal/service.js
import { Service } from 'backbone.service';
const ModalService = Service.extend({
setup(options = {}) {
this.container = options.container;
},
requests: {
show: 'show',
hide: 'hide'
},
show(view) {
this.container.show(view);
},
hide() {
this.container.empty()
}
});
export const modalService = new ModalService();
//main.js
import { App } from './app';
import { modalService } from './modal/service';
const app = new App({
el: '.root-element'
});
modalService.setup({
container: app.layout.modal
});
.... init other components
//someComponent/index.js
import { modalService } from '../modal/service';
...
showView() {
const view = new View();
modalService.request('show', view)
.then(doSomething)
.catch(err => {
console.error(err);
});
},
hideView() {
modalService.request('hide')
.then(doSomething);
}
I try to use jstree control in my TypeScript code for an angularjs application. I use jstree typings and jstree.directive to show a tree. Everything works to the point when I need to handle menu item click and call for the base method. Inside of my action there is no "this" (contextmenu) scope. Any suggestions?
class MapTreeViewController {
mapTreeView: JSTree;
vm.mapTreeView = $('#jstree').jstree(
{
'core': { 'data': items },
'plugins': ['themes', 'ui', 'contextmenu'],
'contextmenu': {
'items': function(node:any) {
var vmNode = this;
return {
'rename': { // rename menu item
'label': 'Rename',
'action': function(obj) {
this.rename(obj);
}
}
};
}
}
});
}
Somewhere inside of a method.
this is not an instance - take a look at the original function to see how to obtain an instance:
https://github.com/vakata/jstree/blob/master/src/jstree.contextmenu.js#L84
"action" : function (data) {
var inst = $.jstree.reference(data.reference),
...