The cellClass function is not called when the component properties change.
How do I kick a rowClass orcellClass?
#Component({
...,
template: `<ngx-datatable [rowClass]="rowClass"></ngx-datatable>`
})
class SomeComponent {
someVariable = true;
rowClass = (row) => {
return {
'some-class': (() => { return this.someVariable === row.someVariable })()
};
}
}
Related
https://github.com/swimlane/ngx-datatable/issues/774
I was able to solve it by changing this.rows.
https://swimlane.gitbook.io/ngx-datatable/cd
this.rows = [...this.rows];
If you are using a store, you need to cancel the immutable attribute.
Example
#Input() set list(list: Record<string, unknown>[]) {
if (list.length) {
// If the search results are reflected in the table.
// And 20 items are loaded at a time.
if (list.length === 20) {
this.rows = list.map((item) => ({ ...item }));
// Load more items
} else {
const newRows = list.map((item) => ({ ...item })).slice(this.rows.length);
this.rows = this.rows.concat(newRows);
}
}
}
I implemented it in sample , it works but in my main project it's displaying error message that backPressed is not a function.
backPressed = () => {
setTimeout(function() {
//Put All Your Code Here, Which You Want To Execute After Some Delay Time.
BackHandler.exitApp();
}, 3000);
};
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.backPressed);
}
componentDidMount() {
BackHandler.addEventListener("hardwareBackPress", this.backPressed);
}
static getDerivedStateFromProps(nextProps, prevState) {
const { userdata } = nextProps.UserDetailReducer;
const { UpdatingFailure } = nextProps.UpdateUserImageReducer;
if (UpdatingFailure) {
return {
avatarSource: ""
};
}
if (userdata.kenkoScore != "" && userdata.kenkoScore > 0) {
setTimeout(() => {
AsyncStorage.setItem("SCORE_FETCHED", "Yes");
nextProps.navigation.navigate("TabNavigation");
}, 100);
return null;
} else {
***this.backPressed();***
}
if (userdata) {
return { userDetail: userdata };
}
return null;
}
In componentDidMount it is working but in getDerivedStateFromProps not working
getDerivedStateFromProps is static so this refers to the class itself, not an instance of the class.
Make backPressed static to call it from getDerivedStateFromProps. You'll also need to update componentWillUnmount and componentDidMount to ComponentName.backPressed or this.constructor.backPressed. Note that making backPressed static means you won't be able to access this for props or state in the future.
I find this code to handle the back button on android :
componentDidMount() {
this.handleAndroidBackButton ();
}
componentWillUnmount () {
this.removeAndroidBackButtonHandler();
}
handleAndroidBackButton = () => {
BackHandler.addEventListener('hardwareBackPress', () => {
this.showModal1(true);
return true;
});
};
removeAndroidBackButtonHandler = () => {
BackHandler.removeEventListener('hardwareBackPress', () => {});
}
it works fine but when I go to the other page, I still have the same behaviour.
I find this on stackoverflow:
constructor() {
this._onBackButton= this._onBackButton.bind(this)
}
_onBackButton() {
return true;
}
and I changed my code to this:
constructor(props){
super(props)
this.state = {
transData: [],
...
}
this._onBackButton = this._onBackButton.bind(this);
}
_onBackButton = () => {
return true;
};
componentDidMount() {
this.handleAndroidBackButton();
...
}
componentWillUnmount () {
this.removeAndroidBackButtonHandler();
}
handleAndroidBackButton = () => {
BackHandler.addEventListener('hardwareBackPress', this._onBackButton);
};
removeAndroidBackButtonHandler = () => {
BackHandler.removeEventListener('hardwareBackPress', this._onBackButton);
}
I don't have any error now but it doesn't work ! it doesn't remove event listener in other screens
The AndroidBakHandler you're having is named _onBackButton ... but you're binding a method called _onBack ... So just rename your backHandler to be _onBackButton and make it arrow-function (Auto bound to your class ... that's why you wouldn't need to bind it in the constructor)
// constructor() {
// No need for the next line ... arrow function is bound automatically
// this._onBackButton = this._onBackButton.bind(this);
// }
_onBackButton = () => {
return true;
};
-
removeAndroidBackButtonHandler = () => {
BackHandler.removeEventListener('hardwareBackPress',
() => {}); // <- look at that
}
Regarding: "It works fine but when I go to the other page, I still have the same behaviour."
It's because when you navigate into another screen (Your component is not unmounted) ... and you're removing your android-back-handler in componentWillUnmount ...
So I'd suggest you remove your event-listener when you navigate to another screen not in componentWillUnmount
Also make sure you have you add your android-back-handler when your screen receives focus again
I’m setting up a new service for navigation to "Chat" service but it doesn't do anything and I don't know why.
This is for a new component
here is the "onCancel" button that use the "getCustomerService" function..
handleUnrecognizedUser = () => {
const infoMsg = {
onCancel: getCustomerService
};
};
here is the "getCustomerService" function that get called
import { AppStore, RoutingStore } from '../../stores'
import call from 'react-native-phone-call'
callServeiceCenter = (number) => {
const args = {
number, // String value with the number to call
prompt: false // Optional boolean property. Determines if the user should be prompt prior to the call
}
return call(args).catch(console.error)
}
export default getCustomerService = () => {
if (AppStore.isWorkingHours)
RoutingStore.goTo('Chat')
else {
callServeiceCenter(AppStore.getCallCenterPhone)
}
}
this is for the "RoutingStore" :
import { observable, action, computed } from "mobx";
import { NavigationActions, StackActions, DrawerActions } from 'react-navigation'
class RoutingStore {
#observable nav = null;
#observable PrevPage = null;
#observable curentPage = null;
#observable isGoBackAvailable = true;
#observable isLoggedIn = false;
#action
setNavigation(data) {
this.nav = data
}
goTo = (data, _params) => {
let { routeName, params } = data
const navigateAction = NavigationActions.navigate(
routeName
? { routeName, params }
: { routeName: data, params: { ..._params } })
this.nav.dispatch(navigateAction)
}
#action
goBack = () => {
}
#action
updateCurrentPage(data) {
this.curentPage = data
}
#action
updatePrevPage(data) {
this.PrevPage = data
}
updatePages = (prev, cur) => {
this.updatePrevPage(prev)
this.updateCurrentPage(cur)
}
#action
setLoggedIn(status) {
this.isLoggedIn = status
}
#action
openDrawer() {
this.nav.dispatch(DrawerActions.openDrawer())
}
#action
closeDrawer() {
this.nav.dispatch(DrawerActions.closeDrawer())
}
#action
toggleDrawer() {
this.nav.dispatch(DrawerActions.toggleDrawer())
}
disableLoginRoute = (route) => {
const resetAction = StackActions.reset({
index: 0,
key: null,
actions: [NavigationActions.navigate({ routeName: route })],
});
this.nav.dispatch(resetAction)
}
isGoBackAllowed = () => {
switch (this.curentPage) {
case "Tabs": return false
case "Login": return false
default: return this.goBack()
}
}
#computed
get isNonLogin() {
return this.isLoggedIn;
}
#computed
get getCurentPage() {
return this.curentPage;
}
}
const routingStore = new RoutingStore();
export default routingStore;
I expect to navigate to the Chat as well.
This is the flow of the application:
The shell.js loads the schoolyeardialog.js which contains the schoolyearbrowser.js which loads the schoolyearwizard.js via create or edit button.
When I repeat these steps multiple times: click create/edit button then I do multiple
requests in my SchoolyearWizard to this:
$.when(service.editSchoolyear(schoolyearId))
The reason is that the subscribed events are not correctly unsubscribed in my opinion.
I have tried different ways of unsubscribing in the SchoolyearDialog.js file.
Either the events did not fire - when I did the subscription.off(); after the app.on(...)
or It was unsubscribed at the wrong position.
Where should I unsubscribe correctly?
If you guys need a sample repo as visual studio solution I can provide this if it helps or maybe you see clearly and immediately the error?!
I have also thought about unsubscribing from the 2 events create/edit when the SchoolyearDialog module is "unloaded" because then both events could/would be unsubscribed not only the create OR edit subscription as it is now when I either click the add or edit button... how would I do that?
SHELL
define(['plugins/router', 'durandal/app', 'viewmodels/SchoolyearDialog', 'knockout'], function (router, app, schoolyearDialog, ko) {
self.schoolyearIsLoaded = ko.observable(false);
var saveTimeTableSubscription = app.on('savedTimeTable').then(function (options) {
// after coming the 2nd time here
if (!self.schoolyearIsLoaded()) {
router.map([{ route: 'lessonplanner', moduleId: 'viewmodels/lessonplanner', title: 'lesson planner', nav: true },
{ route: 'documentbrowser', moduleId: 'viewmodels/documentbrowser', title: 'document browser', nav: true }])
.buildNavigationModel();
self.schoolyearIsLoaded(true);
}
router.navigate("lessonplanner", true);
});
return {
router: router,
activate: function () {
router.map([{ route: '', moduleId: 'viewmodels/SchoolyearDialog', nav: true, title: 'Schoolyearbrowser' }
]).buildNavigationModel();
return router.activate('SchoolyearDialog');
}
};
});
SchoolyearDialog
define(['durandal/app', 'knockout', 'plugins/router', 'viewmodels/SchoolyearWizard'],
function (app, ko, router, wizard) {
var ctor = function () {
debugger;
var self = this;
self.createSubscribe = ko.observable();
self.editSubscribe = ko.observable();
self.activeScreen = ko.observable('viewmodels/SchoolyearBrowser'); // set the schoolyear browser as default module
var createWizardSubscription = app.on('createWizard').then(function () {
self.createSubscribe().off();
self.createSubscribe(null);
self.activeScreen(new wizard('create'));
}, self);
self.createSubscribe(createWizardSubscription);
var editWizardSubscription = app.on('editWizard').then(function (schoolyearId) {
self.editSubscribe().off();
self.editSubscribe(null);
self.activeScreen(new wizard('edit', schoolyearId));
}, self);
self.editSubscribe(editWizardSubscription);
}
return ctor;
});
SchoolyearBrowser
define(['durandal/app', 'plugins/dialog', 'knockout', 'services/dataservice', 'plugins/router'],
function (app, dialog, ko, dataservice, router) {
var SchoolyearBrowser = function () {
var self = this;
self.schoolyears = ko.observableArray();
$.when(dataservice.getSchoolyears())
.done(function (schoolyearModels) {
self.schoolyears(schoolyearModels);
});
self.create = function () {
app.trigger('createWizard');
}
self.edit = function () {
app.trigger('editWizard', 1);
}
};
return SchoolyearBrowser;
});
SchoolyearWizard
define(['durandal/activator', 'viewmodels/step1', 'viewmodels/step2', 'knockout', 'durandal/app', 'services/dataservice', 'viewmodels/CreateEditSchoolyearViewModel'],
function (activator, Step1, Step2, ko, app, service, CreateEditSchoolyearViewModel) {
var ctor = function (viewMode, schoolyearId) {
debugger;
// depending on the mode I could setup 2 different step modules for create and edit ? and the Wizard has one property called content
if (viewMode === 'edit') {
$.when(service.editSchoolyear(schoolyearId))
.done(function (response) {
debugger;
self.viewModel(new CreateEditSchoolyearViewModel(response));
}).fail(function (error) {
alert(error);
});
}
else if (viewMode === 'create') {
$.when(service.createSchoolyear())
.done(function (response) {
debugger;
self.viewModel(new CreateEditSchoolyearViewModel(response));
}).fail(function (error) {
alert(error);
});
}
var self = this;
var steps = [new Step1(viewMode), new Step2(viewMode)];
var step = ko.observable(0); // Start with first step
self.activeStep = activator.create();
var stepsLength = steps.length;
self.viewModel = ko.observable();
this.hasPrevious = ko.computed(function () {
return step() > 0;
});
self.caption = ko.observable();
this.activeStep(steps[step()]);
this.hasNext = ko.computed(function () {
if ((step() === stepsLength - 1) && self.activeStep().isValid()) {
// save
self.caption('save');
return true;
} else if ((step() < stepsLength - 1) && self.activeStep().isValid()) {
self.caption('next');
return true;
}
});
this.isLastStep = function () {
return step() === stepsLength - 1;
}
this.next = function () {
if (this.isLastStep()) {
var vm = this.activeStep(); //.viewModel;
$.when(service.saveCreateSchoolyear({ schoolyearId: 1 })).done(function () {
app.trigger('savedTimeTable', { isSuccess: true });
}).fail(function (e) {
alert(e);
});
}
else if (step() < stepsLength) {
step(step() + 1);
self.activeStep(steps[step()]);
}
}
this.previous = function () {
if (step() > 0) {
step(step() - 1);
self.activeStep(steps[step()]);
}
}
}
return ctor;
});
This helped me greatly:
activator.deactivate function allows the previous object to execute custom deactivation logic."
SchoolyearDialog.js
self.deactivate = function () {
self.createSubscribe().off();
self.editSubscribe().off();
}
When the schoolyearDialog is deactivated both events are unsubscribed independing wether button create/edit is clicked. This is for me a clean solution :)
I agree with your solution but I'd recommend not to use plain .off() without parameters as this will cause to deregister all the events in the application.
Rather pass the event name as a parameter to your off method:
self.createSubscribe().off('savedTimeTable');