Hello,
I have three questions about the Kendo React Editor:
What I want to do is basically an editor that behaves like a normal input field but where I can have a custom dropdown for adding tags, preferably positioned to the right of the "input field".
What I have is an array of "tags" that I want to be able to add to a text field. The tags should be "stylable" like tags I had in a previous question (https://www.telerik.com/forums/creating-a-custom-editor-node-with-html-inside). Other than that I want the field to behave like a regular text field (i.e. no styling, no keyboard shortcuts etc.) and I figured that the easiest way was to create an editor with the above constraints.
Constraints #2 and #3 are most important, I can live without #1 if it's not possible.
Hi, sorry for the broad question.
Im finding it quite hard to stay typed without explicitly casting when using handlers and custom renders (using grid and form). Are there anyway to avoid this?
Hello everyone,
I have a custom dialog editor for the scheduler with three custom DropDownLists as you can see in my code here:
import React, {Component} from "react";
import {FormElement, Field} from '@progress/kendo-react-form';
import {Label, Error} from '@progress/kendo-react-labels';
import {TextArea} from '@progress/kendo-react-inputs';
import {DateTimePicker} from '@progress/kendo-react-dateinputs';
import ProjectsEditor from "./ProjectsEditor";
import VehiclesEditor from "./VehiclesEditor";
import {TokenContext} from "./Context";
import TaskTemplatesEditor from "./TaskTemplatesEditor";
class TaskFormEditor extends Component {
// This line of code is making all the difference, I'm associating the
// context of this component with the context I created!!! :D
static contextType = TokenContext;
constructor(props) {
super(props);
this.state = {
projects: [],
vehicles: [],
taskTemplates: [],
filteredVehicles: [],
filteredTaskTemplates: [],
selectedProjectId: null,
selectedVehicleId: null,
vehiclesDisabled: true,
taskTemplatesDisabled: true
};
this.handleProjectsChange = this.handleProjectsChange.bind(this);
this.handleVehiclesChange = this.handleVehiclesChange.bind(this);
}
handleProjectsChange(event) {
this.setState({
filteredVehicles: this.state.vehicles.filter(vehicle => vehicle.projectId === event.value.id),
vehiclesDisabled: false,
selectedProjectId: event.value.id
});
}
handleVehiclesChange(event) {
this.setState({
filteredTaskTemplates: this.state.taskTemplates.filter(taskTemplate => taskTemplate.vehicleId === event.value.id),
taskTemplatesDisabled: false,
selectedVehicleId: event.value.id
});
}
componentDidMount() {
const config = {
headers: {
"Content-type": "application/json",
"Authorization": `Bearer ${this.context}`,
},
};
axios.get("api/getProjectsVehiclesTaskTemplates?", config)
.then(res => {
this.setState({
projects: res.data[0].map(dataItem => (
{
id: dataItem.id,
projectId: dataItem.project_id
}
)),
vehicles: res.data[1].map(dataItem => (
{
id: dataItem.id,
label: dataItem.label,
projectId: dataItem.project_id
}
)),
taskTemplates: res.data[2].map(dataItem => (
{
id: dataItem.id,
title: dataItem.title,
vehicleId: dataItem.vehicle_id
}
))
});
});
}
render() {
return (
<
FormElement
horizontal={true}>
<
div
className
=
"k-form-field"
>
<
Label
>
Project
</
Label
>
<
div
className
=
"k-form-field-wrap"
>
<
Field
name={"ProjectId"}
component={(props) =>
(<
ProjectsEditor
value={this.state.selectedProjectId}
projects={this.state.projects}
handleChange={this.handleProjectsChange}/>)}
/>
{/*{props.errors.Patient && <
Error
>{props.errors.Patient}</
Error
>}*/}
</
div
>
</
div
>
<
div
className
=
"k-form-field"
>
<
Label
>
Vehicle
</
Label
>
<
div
className
=
"k-form-field-wrap"
>
<
Field
name={"VehicleId"}
component={(props) =>
(<
VehiclesEditor
value={this.state.selectedVehicleId}
vehiclesDisabled={this.state.vehiclesDisabled}
vehicles={this.state.filteredVehicles}
handleChange={this.handleVehiclesChange}/>)}
/>
</
div
>
</
div
>
<
div
className
=
"k-form-field"
>
<
Label
>
Task Template
</
Label
>
<
div
className
=
"k-form-field-wrap"
>
<
Field
name={"TaskTemplateId"}
component={(props) =>
(<
TaskTemplatesEditor
taskTemplatesDisabled={this.state.taskTemplatesDisabled}
taskTemplates={this.state.filteredTaskTemplates}/>)}
/>
{/*{props.errors.Treatment && <
Error
>{props.errors.Treatment}</
Error
>}*/}
</
div
>
</
div
>
<
div
className
=
"k-form-field"
>
<
Label
>
Note
</
Label
>
<
div
className
=
"k-form-field-wrap"
>
<
Field
name={"Comment"}
component={TextArea}
rows={1}
/>
</
div
>
</
div
>
<
div
className
=
"k-form-field"
>
<
Label
>
Start
</
Label
>
<
div
className
=
"k-form-field-wrap"
>
<
Field
name={"Start"}
component={this.props.startEditor}
as={DateTimePicker}
rows={1}
format
=
"t"
/>
</
div
>
</
div
>
<
div
className
=
"k-form-field"
>
<
Label
>
End
</
Label
>
<
div
className
=
"k-form-field-wrap"
>
<
Field
name={"End"}
component={this.props.endEditor}
as={DateTimePicker}
rows={1}
format
=
"t"
/>
</
div
>
</
div
>
</
FormElement
>
);
}
}
export default TaskFormEditor;
And my problem is that when I save the form, I can't get none of these values. I want to retrieve the Field with the names: ProjectId, VehicleId and TaskTemplateId.
To give an example of one, the Field with ProjectId is:
import React, {Component} from "react";
import {DropDownList} from "@progress/kendo-react-dropdowns";
class ProjectsEditor extends Component {
constructor(props) {
super(props);
console.log(this.props);
}
render() {
return (
<
DropDownList
onChange={this.props.handleChange}
value={this.props.projects.find((p) => p.id === this.props.value)}
data={this.props.projects}
dataItemKey={"id"}
textField={"projectId"}
/>
);
}
}
export default ProjectsEditor;
I want to get this information in m
handleDataChange({created, updated, deleted}) {
this.setState({
data: this.state.data.filter((item) => deleted.find(current => current.TaskID === item.TaskID) === undefined)
.map((item) => updated.find(current => current.TaskID === item.TaskID) || item)
.concat(created.map((item) => Object.assign({}, item, {TaskID: guid()})))
});
let data = (created.length !== 0) ? created : (updated.length !== 0) ? updated : deleted;
console.log(data);
let crudId = (created.length !== 0) ? 1 : (updated.length !== 0) ? 0 : -1;
const mechanicId = data[0].PersonIDs;
data = data.map(item => ({
id: item.TaskID,
start_date: this.convertToPhpDateTime(item.Start),
end_date: this.convertToPhpDateTime(item.End),
comment: null,
task_template_id: item.taskTemplateId,
user_time_spent: null,
task_state_id: 2,
priority_id: 3,
periodicity_end_date: null,
created_user_id: this.props.userId,
changed_user_id: this.props.userId,
active: true,
deadline_execution: null
}));
const config = {
headers: {
"Content-type": "application/json",
"Authorization": `Bearer ${this.props.token}`
}
};
/*axios.post("api/saveTask", {
data: data[0],
crudId: crudId,
mechanicId: mechanicId
}, config);*/
}
Thank you very much from your help.
Best Regards,
Daniel
Hello everyone,
I've the following code:
render() {
return (
<
Scheduler
height={"100%"}
data={this.state.data}
onDataChange={this.handleDataChange}
transport={{
token: this.props.token
}}
modelFields={{
id: "TaskID",
title: "Title",
description: "Comment",
start: "Start",
end: "End",
recurrenceRule: "RecurrenceRule",
recurrenceId: "RecurrenceID",
recurrenceExceptions: "RecurrenceException",
token: this.props.token
}}
editItem={TaskItem}
form={TaskForm}
editable={{
add: true,
remove: true,
drag: true,
resize: true,
edit: true
}}
group={{
resources: ["Persons"],
orientation: "horizontal"
}}
resources={[{
name: "Persons",
data: [
{text: "Sascha", value: 35, color: "#5392E4"},
{text: "Alex", value: 39, color: "#5392E4"},
{text: "Leonhard", value: 54, color: "#5392E4"},
{text: "Daniel", value: 91, color: "#5392E4"}
],
field: "PersonIDs",
valueField: "value",
textField: "text",
colorField: "color"
}]}
>
<
DayView
title
=
"Day View"
workDayStart={"05:00"}
workDayEnd={"20:00"}
showWorkHours={true}
slotDuration={60}
slotDivisions={4}
/>
<
WorkWeekView
title
=
"Week View"
workWeekStart={Day.Monday}
workWeekEnd={Day.Friday}
workDayStart={"05:00"}
workDayEnd={"20:00"}
showWorkHours={true}
slotDuration={60}
slotDivisions={4}
/>
</
Scheduler
>
);
}
And I need to pass a Bearer token property to my form you can see on the code above called TaskForm. So that on the TaskForm with the following code I can get this token on the this.props a pass it to other components. I need this so on many of the child components in this form I can make api calls with axios.
class TaskForm extends Component {
constructor(props) {
super(props);
}
/*const requiredValidator = React.useCallback(
(value) => (value === undefined || value === null || value === ''
? 'Field is required.'
: undefined),
[]
);
const formValidator = (_dataItem, formValueGetter) => {
let result = {};
result.Patient = [
requiredValidator(formValueGetter('Patient'))
].filter(Boolean).reduce((current, acc) => current || acc, '');
result.Treatment = [
requiredValidator(formValueGetter('Treatment'))
].filter(Boolean).reduce((current, acc) => current || acc, '');
return result;
};*/
componentDidMount() {
console.log(this.props);
}
render() {
return (
<
SchedulerForm
{...this.props}
editor={TaskFormEditor}
dialog={TaskDialog}
/*validator={formValidator}*/
/>
);
}
}
export default TaskForm;
When I double-click an empty time slot in the Week View, I arrive at the new event editor. The default duration for a new meeting is 15 minutes (likely the result of my slotDivisions and slotDuration properties, see below). I would like this default to be 30 minutes while retaining the behavior where time of day is listed on the left hand side, with slots starting every 15 minutes.
I have my scheduler configured thus:
<Scheduler
data={data}
editable={true}
onDataChange={handleDataChange}
resources={resources}
>
<WeekView slotDivisions={1} slotDuration={15} />
</Scheduler>
Is there a property I can set? Or perhaps is there an event handler I can use to manually tweak the scheduled end time when starting to edit a new event?
Hello,
first I want to say that I have been trying to find the solution in this forum, on StackOverflow and in the examples posted by ProseMirror but so far I have been unable. I have tried some suggestions but non have helped me. If the answer is somewhere I have already looked (or not looked) I apologize.
I have a KendoReact Editor which can be pre-filled with a value from an API. This value can contain "custom tags" looking like this
${some_tag_key}
or like this
<
span
style={{visibility: 'hidden'}}>$</
span
>some_tag_key<
span
style={{visibility: 'hidden'}}>$</
span
>
These tags are used by the API to parse a text for an email, and the editor is used to create difference standardized email templates. An example of a full text coming from the API would be:
<
p
>Hello ${receiver},</
p
>
<
p
>Welcome to this page!</
p
>
<
p
>
Best regards<
br
>
<
span
style={{visibility: 'hidden'}}>$</
span
>sender<
span
style={{visibility: 'hidden'}}>$</
span
>
</
p
>
I also have a list of "custom tags" the user should be able add to the email template using a dropdown. I can focus on either of the above "tag types", and I don't need to support both.
I have some prerequisites:
Therefore I am trying to create a custom node to put these tags in. My thought is that any tags coming from the API should be translated into this custom node, and any tags added using a dropdown should also be this custom node, and when exported to HTML have the code of a tag.
I have focused on the second solution ("<span style={{...") since it looked more straight forward to me, but I'm open to use the other one if it might be easier. This is what I have done so far: [https://stackblitz.com/edit/react-ts-1hlrqt](https://stackblitz.com/edit/react-ts-1hlrqt).
But now I am stuck. I have three questions:
Thanks in advance!
Hey everyone,
I'm considering KenoReact for some upcoming projects. It looks like an excellent component library.
I have one question regarding themes. Judging by the documentation it appears that themes can only be customized by overwriting SCSS variables directly within the SCSS file before the theme is imported. Theme customization in general appears somewhat limited in that there doesn't seem to be any way to programmatically override the theme.
For instance, if I wanted to allow a client to pick their own theme colours via a colour picker, save the colours to DB and then use those values in the theme I don't see any clear way to do this. For instance this type of implementation would be possible with Material-UI theming. One possibility is to use the styled components integration to override the theme? Though I imagine this might be somewhat cumbersome.
Any insight would be appreciated, thank you!
Hello,
Yesterday I got great help from Nikolay in creating a custom editor node, see https://www.telerik.com/forums/creating-a-custom-editor-node-with-html-inside. Now I would like to extend his solution so that when a user types (for example) `${name}`, it will be converted into my new node.
I looked at https://www.telerik.com/kendo-react-ui/components/editor/plugins/#toc-input-rules and tried to add this to the code solution from Nikolay. This is my StackBlitz so far: https://stackblitz.com/edit/react-y3dx71-uqujbr?file=app%2Fmain.jsx
On line 55, I added code for creating the new rule, and on line 78 I add the new rule to the editor plugins. But this does not seem to work, when I input something that I thought would match the rule, nothing happens.
What am I doing wrong here?
Also, I would like to add a condition to the rule: It should only be converted if the text matches one of the "code" props in the "shortcodes" array in InsertShortcodeTool.tsx. I tried looking at match property in the input rules documentation, but honestly I don't understand how it works.
I ran into the same problem illustrated here: https://www.telerik.com/forums/inline-cell-edit-functional
However the solution is unusable with large lists (even with paging) due to the obvious iterations, the lag between character inputs is horrendous. This is not an issue with other inputs such as the number input editor, only the text editor. Has there been any discussion surrounding this, the input control should keep track of this independently instead of needing to cycle through the entire data list on every keystroke.
Thanks