How to write custom sort logic on sort column event in ng2-smart-table - ng2-smart-table

I'm looking to hook-up sort events performed on ng2-smart-table. Followed https://akveo.github.io/ng2-smart-table/#/documentation, I see bunch of events that are exposed like rowSelect, mouseover etc but I don't see sort events published/emitted by the library. I'm thinking of changing Ng2SmartTableComponent and emit an event when (sort) is called internally. May I know if anyone did it already or is there a hack I can rely upon.

The source of the sort in ng2-smart-table is shown on GitHub (link to code).
If you want to change the compare-Function (as used by default) you can add your own custom function in your ng2-smart-table-configuration:
columns: {
group_name: {
title: 'Groupname',
compareFunction(direction: any, a: any, b: any) => {
//your code
}
}
}

I was searching for an event to sort my data remotely and I have found a solution. Also I have some logic for page change event (remote paging). Here is what works for me.
ts
source: LocalDataSource = new LocalDataSource();
ngOnInit() {
this.source.onChanged().subscribe((change) => {
if (change.action === 'sort') {
this.sortingChange(change.sort);
}
else if (change.action === 'page') {
this.pageChange(change.paging.page);
}
});
}
html
<ng2-smart-table [settings]="settings" [source]="source"></ng2-smart-table>
This solution won't replace custom logic but it might help you solve your problem.

Related

How to improve ui Sentry.io breadcrumbs?

I was wondering if there is a good practice on how to write your HTML code in order to get better Sentry.io breadcrumbs inside of the issues.
It's not possible to identify the elements that the user has interacted and I think using CSS class or IDs for it is not the ideal - although we can customize the breadcrumbs, looks like it's not a good practice to get the text inside the tag as per some issues found on Sentry Github repository.
I was thinking about aria-label, does anyone has any advices on it?
Right now is very hard to understand the user steps when reading the breadcrumbs.
This can be solved using the beforeBreadcrumb hook / filtering events.
Simply add
beforeBreadcrumb(breadcrumb, hint) {
if (breadcrumb.category === 'ui.click') {
const { target } = hint.event;
if (target.ariaLabel) {
breadcrumb.message = target.ariaLabel;
}
}
return breadcrumb;
}
... to your Sentry.init() configuration.
Sentry.init({
dsn:...
Resulting in something like this:
Sentry.init({
dsn: '....',
beforeBreadcrumb(breadcrumb, hint) {
if (breadcrumb.category === 'ui.click') {
const { target } = hint.event;
if (target.ariaLabel) {
breadcrumb.message = target.ariaLabel;
}
}
return breadcrumb;
}
});
More about this here: sentry.io filtering events documentation

FullCalendar-Scheduler Google Calendars ResourceIDs Query

Reference: FullCalendar 3.9.0, FullCalendar-Scheduler 1.9.4
Can anyone confirm whether or not it is possible to group Google calendar events by resource? Adding a resourceId parameter to a calendar source as follows:
var myCalSrc = {
id: 1,
googleCalendarId: '<myCalSrcURL>',
color: '<myCalSrcColor>',
className: '<myCalSrc-events>'
};
results in a blank display. The following note in the FullCalendar-Scheduler gcal.html file located in the demos directory states:
/*
NOTE: unfortunately, Scheduler doesn't know how to associated events from
Google Calendar with resources, so if you specify a resource list,
nothing will show up :( Working on some solutions.
*/
However, the following threads appear to suggest there may have been a fix for this:
GitHub - Add ResourceId Parameter to gcal.js (fix supplied)
GitHub - Specify resourceId in Event Source settings
However, checking the gcal.js file reveals the fix has not been added to that file.
Is it possible to manually assign a resourceId to each of the Google Calendar feeds in order to replicate the Resources and Timeline view indicated by the FullCalendar Timeline View documentation?
Any guidance would be greatly appreciated.
As per the issue in your second GitHub link (which your first one was merged with), https://github.com/fullcalendar/fullcalendar-scheduler/issues/124, the fix you mentioned is still awaiting testing (as of 11 Mar 2018). So if you're patient it will likely be added to a future release, assuming it passes the tests. In the meantime, here is a potential workaround:
In fullCalendar it's possible to define a separate eventDataTransform for every event source.
Therefore I think you should be able to use this to set a resource ID for each event depending on the Google Calendar it came from:
eventSources: [
{
googleCalendarId: 'abc#group.calendar.google.com',
color: 'blue',
eventDataTransform: function(event) {
event.resourceId = 1;
return event;
}
},
{
googleCalendarId: 'def#group.calendar.google.com',
color: 'green',
eventDataTransform: function(event) {
event.resourceId = 2;
return event;
}
},
{
googleCalendarId: 'ghi#group.calendar.google.com',
color: 'red' ,
eventDataTransform: function(event) {
event.resourceId = 3;
return event;
}
}
]
I'm not able to test this right now but it looks like it should work. Hopefully this will take place before it's rendered on the calendar and needs to belong to a resource.

Keyup event fire multipletime

Currently, I am working on Angular 4 app. In my component Html, I have one textbox. Whenever user first type anything I want to make an API call to get some data.
The issue is if User type 'A' then it is working fine and calling API. But when user type "ABC" it is making API call 3 times. Instead of making API call for every letter, only one call should be made.
Please suggest any solution.
Component's HTML :
<input id="inputbox" (keyup)="keyUp($event)"/>
Component :
data: string[]
keyUp(event: any) {
this.loadDataApiCall();
}
loadDataApiCall() {
// calling api to load data.
//fill data into
}
Can I solve this issue with help of RXjs in angular 4
Observable.fromEvent(yourDomElement, 'keyup').auditTime(100).subscribe(()=>{
doSomething();
});
You should probably add a timeout to your call and clear it every time it is triggered so only the last call is called.
data: string[]
keyUp(event: any) {
window.clearTimeout(window.apiCallTimeout);
window.apiCallTimeout = window.setTimeout(this.loadDataApiCall, 100);
}
loadDataApiCall() {
// calling api to load data.
//fill data into
}
This means of course that the call will be done 100ms after the user stops typing. Also if he types "a" and after a while he types "bc", then two calls will be made. Of course you can increase the delay to meet your requirements.
If you only want one API call you can use the blur event, which is emitted when the control loses focus:
<input id="inputbox" (blur)="keyUp($event)"/>
Try this:
keyUp(event: any) {
this.loadDataApiCall();
event.stopImmediatePropagation();
}
the right way to implement this is by registering the event and calling the API after sometime while saving the latest value and checking that the last registered value matches the latest registered value
so in your keyup
keyUp(event: any) {
this.latestValue = event.target.value;
this.registerApiCall(event.target.value);
}
register func
registerApiCall(value){
setTimeout(this.loadDataApiCall.bind(this), 500, value)
}
api call
loadDataApiCall(value) {
if (this.latestValue == value ){
// calling api to load data.
//fill data into
}
}
see working example in this plnk
EDIT:
Observable.fromEvent(yourDomElement, 'keyup').auditTime(100).subscribe(()=>{
doSomething();
});
by é™ˆæšćŽ is the RxJs implementation that looks much better, and here is a working plnkr
If you're willing to change your form to Reactive Forms this would be extremely easy
this.form.get("input").valueChanges.debounceTime(1000).subscribe((value) => {});
Reactive Forms gives you access to observables of value changes and status changes. We're basically subscribing to that observable which emits the value any time it changes and we add a delay of one second so that if the user is still typing and changing the value then it will not execute the code in our subscribe.
#Component({
selector: 'my-app',
template: `
<div>
<input type="text" (keyup)='keyUp.next($event)'>
</div>
,
})
export class App {
name:string;
public keyUp = new Subject<string>();
constructor() {
const subscription = this.keyUp
.map(event => event.target.value)
.debounceTime(1000)
.distinctUntilChanged()
.flatMap(search => Observable.of(search).delay(500))
.subscribe(console.log);
}
}

React upgrade: "this" visibility in getDefaultProps

I am upgrading some older react component I inherited (v0.10.0) to work with the latest version of react (v0.14.8).
The following scenario stopped working:
// within a react component
onClick: function() {
// DO SOMETHING
}
getDefaultProps: function () {
return {
someProp: 'prop',
onClick: this.onClick
}
}
This is easily resolved moving the code into an anonymous function, like the following:
getDefaultProps: function () {
return {
someProp: 'prop',
onClick: function() {
//DO SOMETHING
}
}
}
My question is: why has the visibility of 'this' changed at that level and what's the best way to refactor this code? And what if I had-to/wanted-to use 'this' at that level?
Any help appreciated, as a disclaimer I am a react super-beginner!
The result of getDefaultProps() is shared across all instances of a component. That means that the result can't rely on any particular instance of the component. The reason it changed is likely because of the performance benefit from caching, although I can't say for sure.
As for refactoring the code, I'm not sure there's a silver-bullet here. From my perspective what you currently have seems like an anti-pattern. Props are meant to be passed in by consumers that have no knowledge of the inner workings of the component, so it seems odd that a default value for a prop would depend on the inner workings. Without knowing exactly what you're doing, I would say your best bet is to just use null as the default value for the prop, then check the value at runtime when you do have access to the this context.
handleSomeAction() {
if (!this.props.onClick) {
// DO SOMETHING
}
}

2-way data binding in native web components

I've been reading up on web components and am pretty intrigued by the nascent spec. Does anyone know if there is any support for 2-way data binding in the DOM, without having to use Polymer? An example would be appreciated.
Object.observe is a potential new way to do databinding in javascript. This feature is scheduled for Ecmascript 7(javascript), but some browsers currently support it, check here. Also check out this html5rocks article on object.observe
No, data binding isn't part of the Web Components spec.
You can of course implement data binding yourself using native JavaScript event listeners, and possibly the Proxy object, but it's probably best not to re-invent the wheel: if you want data binding, choose one of the many JavaScript frameworks out there which supports that. Polymer, React, Angular, and Vue are some recent examples of such libraries.
I've been playing around with this over the last few days. You can create a StateObserver class, and extend your web components from that. A minimal implementation looks something like this:
// create a base class to handle state
class StateObserver extends HTMLElement {
constructor () {
super()
StateObserver.instances.push(this)
}
stateUpdate (update) {
StateObserver.lastState = StateObserver.state
StateObserver.state = update
StateObserver.instances.forEach((i) => {
if (!i.onStateUpdate) return
i.onStateUpdate(update, StateObserver.lastState)
})
}
}
StateObserver.instances = []
StateObserver.state = {}
StateObserver.lastState = {}
// create a web component which will react to state changes
class CustomReactive extends StateObserver {
onStateUpdate (state, lastState) {
if (state.someProp === lastState.someProp) return
this.innerHTML = `input is: ${state.someProp}`
}
}
customElements.define('custom-reactive', CustomReactive)
class CustomObserved extends StateObserver {
connectedCallback () {
this.querySelector('input').addEventListener('input', (e) => {
this.stateUpdate({ someProp: e.target.value })
})
}
}
customElements.define('custom-observed', CustomObserved)
<custom-observed>
<input>
</custom-observed>
<br />
<custom-reactive></custom-reactive>
fiddle here
I like this approach because it occurs directly between precisely those elements you want to communicate with, no dom traversal to find data- properties or whatever.
One way: $0.model = {data}; setter on $0 assigns $0.data, responding to the update, and the other way: $1.dispatchEvent(new CustomEvent('example', {detail: $1.data, cancelable: true, composed: true, bubbles: true})); with $0.addEventListenever('example', handler) gives 2 way data binding. The data object is the same, shared on 2 elements, events and setters allow responding to updates. To intercept updates to an object a Proxy works model = new Proxy(data, {set: function(data, key, value){ data[key] = value; ...respond... return true; }}) or other techniques. This addresses simple scenarios. You might also consider looking at and reading the source for Redux, it provides conventions that seem relatively popular. As Ajedi32 mentions reinventing the wheel for more complex scenarios is not so practical, unless it's an academic interest.