Custom list blot not work IndentClass (quilljs) - quill

I create custom blot,
but for some reason the creation of child items does not work when you press tab at the list item. IndentClass does not work and I do not understand how to connect it. Path IndentClass - quill\formats\indent
// eslint-disable-next-line no-unused-vars
import Quill, { ListItem } from 'quill';
let Block = Quill.import('blots/block');
let Container = Quill.import('blots/container');
class NumberListContainer extends Container {}
NumberListContainer.blotName = 'c-number-list-container';
NumberListContainer.tagName = 'OL';
class NumberListItem extends Block {
static create(value) {
const node = super.create();
console.log(typeof value, value, 'value');
node.setAttribute('data-list', value);
return node;
}
static formats(domNode) {
return domNode.getAttribute('data-list') || undefined;
}
static register() {
Quill.register(NumberListContainer);
}
constructor(scroll, domNode) {
console.log( 'value111');
super(scroll, domNode);
const ui = domNode.ownerDocument.createElement('span');
// eslint-disable-next-line no-unused-vars
const listEventHandler = e => {
if (!scroll.isEnabled()) return;
const format = this.statics.formats(domNode, scroll);
if (format === 'checked') {
this.format('list', 'unchecked');
e.preventDefault();
} else if (format === 'unchecked') {
this.format('list', 'checked');
e.preventDefault();
}
};
ui.addEventListener('mousedown', listEventHandler);
ui.addEventListener('touchstart', listEventHandler);
this.attachUI(ui);
}
format(name, value) {
if (name === this.statics.blotName && value) {
this.domNode.setAttribute('data-list', value);
} else {
super.format(name, value);
}
}
}
NumberListItem.blotName = 'c-number-list';
NumberListItem.tagName = 'LI';
NumberListItem.className = 'c-number-list';
NumberListContainer.allowedChildren = [NumberListItem];
NumberListItem.requiredContainer = NumberListContainer;
Quill.register(NumberListContainer);
Quill.register(NumberListItem);

Related

i18next not working with webComponent and shadowRoot - React.JS

I have a problem with validations in dynamically added webComponent in shadowRoot. This validations with translate is working properly in normal Virtual DOM but when i want to dynamically add validations result to Shadow DOM, i18next return not translated value.
In Normal DOM this line
this.message = t(FormApplicationResources.ValidationErrorRequired); return valid string text from database in proper language, but in Shadow DOM same code fragment return key value from DB (not translated)
...
import { t } from "i18next";
class PasswordValidator implements IValidator {
private readonly message: string;
private readonly validPasswordCharactersRegex: RegExp = /[a-zA-Z0-9!##$&()'%*{}\[\]~:;?\-|<>=\\-`.+,/\"]/g;
public type: ValidatorType = ValidatorType.Required;
public constructor(message?: string) {
if (message) {
this.message = message;
} else {
this.message = t(FormApplicationResources.ValidationErrorRequired);
}
}
public validate(value: any, callbacks: ICallbacks): IValidResult {
...
}
}
export default PasswordValidator;
I am using attachchShadow with open mode but does not make any difference.
...
connectedCallback(): void {
this.loadAllAttributes();
const props: any = this.props();
...
this.createPoint();
...
this.render();
}
render(): void {
const props: any = this.props();
if (props.apiEndpoint && props.baseName && props.baseUrl && props.instanceName) {
ReactDOM.render(
<App
lang={props.lang ? props.lang : DEFAULT_SYSTEM_CULTURE}
{...props}
/>
, this.mountPoint
);
}
}
createPoint(): void {
if (!this.mountPoint) {
const shadow: ShadowRoot = this.attachShadow({ mode: "open" });
this.mountPoint = document.createElement("div");
this.mountPoint.id = "Example";
this.mountPoint.style.boxSizing = "example";
shadow.appendChild(this.mountPoint);
...
}
}

change state variable (array of objects) in react

I am very new to react and have a very straightforward usecase.
on a certain function call, I need to update one of the state variables - which is an array of objects.
I need to iterate through this array find an element and add a key the object in that element.
I tried this way but its not working.
const [finalStudents, setFinalStudents] = useState([]);
function setAttentionForStudent(deviceName, value) {
// console.log("Device ID:", deviceName)
// console.log("Attention value:", value)
finalStudents.map((student, index) => {
console.log("student", student)
if (student['device']['deviceName'] == deviceName) {
console.log("student inside", student)
setFinalStudents((prevFinalStudents) => {
console.log("prev final student",prevFinalStudents)
prevFinalStudents[index]['device']['attentionValue'] = value
})
// student['device']['attentionValue'] = value
} else {
setFinalStudents((prevFinalStudents) => {
prevFinalStudents[index]['device']['attentionValue'] = 0
})
}
})
// console.log(finalStudents)
}
Try this:
const [finalStudents, setFinalStudents] = [];
const setAttentionForStudent = (deviceName, value) => {
if (finalStudents.length !== 0) {
for (var x = 0; x < finalStudents.length; x++) {
if (finalStudents[x].device.deviceName === deviceName) {
finalStudents[x].device.deviceName = value;
setFinalStudents(new Array(...finalStudents));
} else {
finalStudents[x].device.deviceName = value;
setFinalStudents(new Array(...finalStudents));
}
}
}
};
callback in setFinalStudents should return an array to update state. You can use map in setFinalStudents like this:
setFinalStudents((prevFinalStudents) => {
return prevFinalStudents.map((student) => {
if (student["device"]["deviceName"] == deviceName) {
student["device"]["attentionValue"] = value;
} else {
student["device"]["attentionValue"] = value;
}
return student;
});
});
Was finally able to solve the problem by the following way:
setFinalStudents((prevFinalStudents) => {
const clonedFinalStudents = [...prevFinalStudents];
return clonedFinalStudents.map((student) => {
let updatedStudent = { ...student };
let attentionValue = 0;
if (student['device']['deviceName'] == deviceName) {
attentionValue = value;
}
updatedStudent = {
...updatedStudent,
device: {
...updatedStudent.device,
attentionValue,
},
};
return updatedStudent;
});
});

Why do I keep getting error while pushing data to Array in Angular 10?

I'm trying to create Angular Material Chips as shown on the site, but I keep getting this error about the array being null.
Here's the component
import { Component, Input, OnInit } from '#angular/core';
import { ActivatedRoute } from '#angular/router';
import { IStatement } from 'src/Interface/ICorporateStatement';
import { StatementService } from '../services/statement.service';
import { MatChipInputEvent } from '#angular/material/chips';
import {COMMA, ENTER} from '#angular/cdk/keycodes';
export interface Tag{
corporate_statement_link_id: number;
name: string;
}
#Component({
selector: 'app-statement-detail',
templateUrl: './statement-detail.component.html',
styleUrls: ['./statement-detail.component.css']
})
export class StatementDetailComponent implements OnInit {
statement: IStatement;
id: number;
tags: Tag[] = [];
visible = true;
selectable = true;
removable = true;
addOnBlur = true;
readonly separatorKeysCodes: number[] = [ENTER, COMMA];
constructor(private statementService: StatementService,
private router:ActivatedRoute) { }
ngOnInit(): void {
this.tags = [
{ corporate_statement_link_id: 1, name: 'EDI'}
];
console.log("Tags: ", this.tags);
this.router.queryParams.subscribe(param => {
this.id = param.id;
this.getStatement(this.id);
});
}
addTag(event: MatChipInputEvent): void {
console.log(this.tags);
const input = event.input;
const value = event.value;
console.log("Input: ", input);
console.log("Value: ", value);
console.log("Tags: ", this.tags);
this.tags.push({corporate_statement_link_id: this.statement.corporate_statement_link_id, name: value.trim()});
// // Add our fruit
// if ((value || '').trim()) {
// this.fruits.push({name: value.trim()});
// }
// // Reset the input value
// if (input) {
// input.value = '';
// }
}
removeTag(tag: Tag): void {
console.log("removing");
// const index = this.fruits.indexOf(fruit);
// if (index >= 0) {
// this.fruits.splice(index, 1);
// }
}
// get statement
getStatement(id){
this.statementService.getStatement(id).subscribe(data => {
this.statement = <IStatement>data[0];
//get tags
this.statementService.getTags(this.statement.corporate_statement_link_id)
.subscribe(tag => {
this.tags = <Tag[]>tag;
})
}, error => {
console.log(error);
});
}
}
I've refactored the code and moved things here and there, but still can't figure out why the array is still null.
It looks like this code is setting this.tags to null.
.subscribe(tag => {
this.tags = <Tag[]>tag;
})
It may be an issue with your <Tag[]> cast, or maybe the data coming back is null?
if it is expected you could replace any null value here with an empty array like this:
.subscribe(tag => {
this.tags = <Tag[]>tag || [];
})
and see if that helps.

Why is my object type not getting updated?

I'm creating a permission service using react typescript and I ran into the following problem. I have the class:
import {IPermission} from "../interfaces/IPermission";
class PermissionService {
private permissions: IPermission[] = [];
constructor(permissions: IPermission[]) {
this.permissions = permissions;
}
public getValue(key: string): IPermission['value'] {
const perm = this.permissions.find(permission => permission.key === key);
if (!perm) {
throw new Error('Could not find the permission');
}
return perm.value;
}
public modifyPermission(key: string, defaultValue: any, value: any): void {
const perms = [...this.permissions];
for (let i = 0; i < perms.length; i++) {
perms[i].defaultValue = defaultValue;
perms[i].value = value
}
this.permissions = perms;
console.log(perms);
}
public parseActivePermissions(permissions: IPermission[]): IPermission[] {
this.permissions.forEach(permission => {
permissions.forEach(activePermission => {
if (permission.key === activePermission.key) {
permission.defaultValue = activePermission.defaultValue;
permission.value = activePermission.value;
}
})
})
return this.permissions;
}
public getAll(): IPermission[] {
return this.permissions;
}
}
export default PermissionService;
and an AdminPermissions data file
import PermissionService from "../services/permission.service";
import {IPermission} from "../interfaces/IPermission";
import Permissions from "./Permissions";
const service: PermissionService = new PermissionService(Permissions);
service.modifyPermission('canAccessAcp', true, true);
const AdminPermissions: IPermission[] = service.getAll();
export default AdminPermissions;
The problem is, the service.modifyPermission() does not update the defaultValue and value of the permission. It's still false when console logging. Why is that?
UPDATE #1
Changed the file a bit. Still doesn't work. Now I'm directly changing the values, but they still log as false.
class AdminPermissions {
public getAll(): IPermission[] {
const service: PermissionService = new PermissionService(Permissions);
service.permissions.forEach(permission => {
if (permission.key === 'canAccessAcp') {
permission.defaultValue = true;
permission.value = true;
}
})
return service.permissions;
}
}
The problem is that with forEach you are not changing the actual value of each items, so you should do something like this:
class AdminPermissions {
public getAll(): IPermission[] {
const service: PermissionService = new PermissionService(Permissions);
return service.permissions.map(permission => {
if (permission.key === 'canAccessAcp') {
return (
{
...permission,
defaultValue: true,
value: true
}
)
}
return permission
});
}
}
I found a solution.
In the permission.service.ts
public modifyPermission(key: string, defaultValue: any, value: any): void {
const perms: IPermission[] = this.permissions.map(permission => {
if (permission.key === key) {
console.log('found permission');
return {
...permission,
defaultValue,
value
}
}
return permission
})
this.permissions = perms;
}

TypeError: Cannot read property 'length' of null in react component

Okay so I've gotten pretty far in creating the React Component for ChartJS, however when testing I get the following error:
FAIL lib\chart\chart.test.tsx
● renders without crashing
TypeError: Cannot read property 'length' of null
at Object.acquireContext (node_modules/chart.js/src/platforms/platform.dom.js:189:19)
at Chart.construct (node_modules/chart.js/src/core/core.controller.js:72:27)
at new Chart (node_modules/chart.js/src/core/core.js:7:8)
at Chart.Object.<anonymous>.Chart.renderChart (lib/chart/chart.tsx:233:26)
at Chart.Object.<anonymous>.Chart.componentDidMount (lib/chart/chart.tsx:42:10)
at node_modules/react-dom/lib/ReactCompositeComponent.js:264:25
at measureLifeCyclePerf (node_modules/react-dom/lib/ReactCompositeComponent.js:75:12)
at node_modules/react-dom/lib/ReactCompositeComponent.js:263:11
at CallbackQueue.notifyAll (node_modules/react-dom/lib/CallbackQueue.js:76:22)
at ReactReconcileTransaction.close (node_modules/react-dom/lib/ReactReconcileTransaction.js:80:26)
at ReactReconcileTransaction.closeAll (node_modules/react-dom/lib/Transaction.js:209:25)
at ReactReconcileTransaction.perform (node_modules/react-dom/lib/Transaction.js:156:16)
at batchedMountComponentIntoNode (node_modules/react-dom/lib/ReactMount.js:126:15)
at ReactDefaultBatchingStrategyTransaction.perform (node_modules/react-dom/lib/Transaction.js:143:20)
at Object.batchedUpdates (node_modules/react-dom/lib/ReactDefaultBatchingStrategy.js:62:26)
at Object.batchedUpdates (node_modules/react-dom/lib/ReactUpdates.js:97:27)
at Object._renderNewRootComponent (node_modules/react-dom/lib/ReactMount.js:319:18)
at Object._renderSubtreeIntoContainer (node_modules/react-dom/lib/ReactMount.js:401:32)
at Object.render (node_modules/react-dom/lib/ReactMount.js:422:23)
at Object.<anonymous> (lib/chart/chart.test.tsx:7:12)
at Promise (<anonymous>)
at Promise.resolve.then.el (node_modules/p-map/index.js:42:16)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:169:7)
× renders without crashing (275ms)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 0 total
Time: 1.314s, estimated 3s
Ran all test suites related to changed files.
However, I've spent a long time looking over the code and haven't been able to figure out why it refuses to work properly. The error starts at the renderChart() function at creating a new chart instance. My first guess would be the for some reason it's not registering the canvas element despite being called by its id. But when the content of renderChart is moved into the render() function it still gives the same error. Here's the code being tested:
import * as React from 'react'
import * as ClassNames from 'classnames'
import * as ChartJS from 'chart.js'
const IsEqual = require('lodash.isequal')
const Find = require('lodash.find')
const subChart = require('chart.js')
interface IChartProps {
/** The user-defined classes */
readonly className?: string
readonly width?: number
readonly height?: number
readonly reRender?: boolean
readonly type: ChartJS.ChartType
readonly data: ChartJS.ChartData
readonly options: ChartJS.ChartOptions
readonly getDatasetAtEvent?: Function
readonly getElementAtEvent?: Function
readonly getElementsAtEvent?: Function
readonly onElementsClick?: Function
readonly datasetKeyProvider?: Function
}
interface IChartState {
/** Add your states here */
}
export class Chart extends React.Component<IChartProps, IChartState> {
// tslint:disable-next-line
private chartInstance: any
private shadowData: {}
constructor(props: IChartProps) {
super(props)
}
public componentWillMount() {
// this.chartInstance = undefined
}
public componentDidMount() {
this.renderChart()
}
// public componentWillReceiveProps(nextProps: IChartProps) {}
public shouldComponentUpdate(nextProps: IChartProps, nextState: IChartState) {
const props = this.props
if (nextProps.reRender === true) {
return true
}
if (props.height !== nextProps.height || props.width !== nextProps.width) {
return true
}
if (props.type !== nextProps.type) {
return true
}
if (!IsEqual(props.options, nextProps.options)) {
return true
}
const nextData = this.transformDataProp(nextProps)
if (!IsEqual(this.shadowData, nextData)) {
return true
}
return false
}
// public componentWillUpdate(nextProps: IChartProps, nextState: IChartState) {}
public componentDidUpdate(prevProps: IChartProps, prevState: IChartState) {
if (this.props.reRender) {
this.chartInstance.destroy()
this.renderChart()
return
}
this.updateChart()
}
public transformDataProp(props: IChartProps) {
const data = props.data
if (typeof data === 'function') {
const node = document.getElementById('bar-chart') as HTMLCanvasElement
return data(node)
} else {
return data
}
}
public memoizeDataProps(props?: IChartProps) {
if (!this.props.data) {
return
}
const data = this.transformDataProp(this.props)
this.shadowData = {
...data,
datasets:
data.datasets &&
data.datasets.map((set: string[]) => {
return { ...set }
})
}
return data
}
public updateChart() {
const options = this.props.options
const data = this.memoizeDataProps(this.props)
if (!this.chartInstance) {
return
}
if (options) {
this.chartInstance.options = subChart.helpers.configMerge(
this.chartInstance.options,
options
)
}
let currentDatasets =
(this.chartInstance.config.data &&
this.chartInstance.config.data.datasets) ||
[]
const nextDatasets = data.datasets || []
const currentDatasetKeys = currentDatasets.map(
this.props.datasetKeyProvider
)
const nextDatasetKeys = nextDatasets.map(this.props.datasetKeyProvider)
const newDatasets = nextDatasets.filter(
(d: object) =>
currentDatasetKeys.indexOf(this.props.datasetKeyProvider(d)) === -1
)
for (let idx = currentDatasets.length - 1; idx >= 0; idx -= 1) {
const currentDatasetKey = this.props.datasetKeyProvider(
currentDatasets[idx]
)
if (nextDatasetKeys.indexOf(currentDatasetKey) === -1) {
// deleted series
currentDatasets.splice(idx, 1)
} else {
const retainedDataset = Find(
nextDatasets,
(d: object) => this.props.datasetKeyProvider(d) === currentDatasetKey
)
if (retainedDataset) {
// update it in place if it is a retained dataset
currentDatasets[idx].data.splice(retainedDataset.data.length)
retainedDataset.data.forEach((point: number, pid: number) => {
currentDatasets[idx].data[pid] = retainedDataset.data[pid]
})
// const { data, ...otherProps } = retainedDataset
currentDatasets[idx] = {
data: currentDatasets[idx].data,
...currentDatasets[idx],
...retainedDataset.otherProps
}
}
}
}
// finally add any new series
newDatasets.forEach((d: object) => currentDatasets.push(d))
const { datasets, ...rest } = data
this.chartInstance.config.data = {
...this.chartInstance.config.data,
...rest
}
this.chartInstance.update()
}
public componentWillUnmount() {
this.chartInstance.destroy()
}
public onClickEvent = (event: React.MouseEvent<HTMLCanvasElement>) => {
// this.props.getDatasetAtEvent &&
this.props.getDatasetAtEvent(
this.chartInstance.getDatasetAtEvent(event),
event
)
// this.props.getElementAtEvent &&
this.props.getElementAtEvent(
this.chartInstance.getElementAtEvent(event),
event
)
// this.props.getElementsAtEvent &&
this.props.getElementsAtEvent(
this.chartInstance.getElementsAtEvent(event),
event
)
// this.props.onElementsClick &&
this.props.onElementsClick(
this.chartInstance.getElementsAtEvent(event),
event
)
}
public render() {
const className = ClassNames('chart', this.props.className)
// bar.update()
return (
<div className={className}>
<canvas
id="chart-instance"
width={this.props.width ? this.props.width : '400'}
height={this.props.height ? this.props.height : '400'}
onClick={this.onClickEvent}
/>
</div>
)
}
public renderChart() {
const { options, type, data } = this.props
const node = document.getElementById('chart-instance') as HTMLCanvasElement
// const data = this.memoizeDataProps()
this.chartInstance = new ChartJS(node, {
type,
data,
options
})
}
}
can someone help me figure out why this won't work properly?
It might because of this:
currentDatasets[idx].data.splice(retainedDataset.data.length)
You should have a check on retainedDataset.data also:
if (retainedDataset && retainedDataset.data) { ... }

Resources