I have several fields on a form. Some of them are simple inputs, others are datetimepickers, a few of them are CKEditors. I handle the form submit manually, so I need to manually update the source fields for the CKEditor instances to get all modification before I save it to a MySQL database. I put all the instances to an array (I see its content in Chrome's web developer tool), but when I try to use destroy or updateSourceElement methods on one item from this array, I get "TypeError, item.updateSourceElement is not a function" messages.
I use this code:
const CKeditors = {};
...
function createEditor( elementId ) {
return ClassicEditor
.create( document.querySelector( elementId ),
{
toolbar: [ "heading", "|", "bold", "italic", "link", "bulletedList", "numberedList"]
})
.then( editor => {
CKeditors[ elementId ] = editor;
})
.catch( err => console.error( err.stack ) );
}
createEditor("#'.$mezo['mezonev'].'_tartalom"); // $mezo['mezonev'].'_tartalom is the unique name of the input field
function submitAllCKeditors(){
for (item in CKeditors)
{
item.updateSourceElement();
}
}
...
and somewhere later when I handle the onlick event, I call "submitAllCKeditors();" I see the array's content with the proper ids, but I get error for the item.updateSourceElement();
What am I doing wrong?
Related
I have Kartik gridView and custom filter. After gridfilter in my browser i got URL like
localhost:20024/consignment?fid=&post_code=&pud2_mrn=&pud2_status=PUDP&pud_status=&pud2_remaining_date=&mrn=&mrn_status=&ioss_number=&declaration_type=&status=&entry_at=&exit_at=&created_at=
Is there a way to remove unfilled parameters from url inside YII instead javascript?
Or can anybody provide full example of javascript to achieve the goal.
Copy vendor/yiisoft/yii2/yii.gridView.js somewhere under web directory (e.g. web/js and add this line:
$.each(data, function (name, value) { if (value[0].length === 0) data[name] = null; });
prior this line in applyFilter method:
var pos = settings.filterUrl.indexOf('?');
Then add this to web.conf (update paths if you used different place for this js file):
'assetManager' => [
'bundles' => [
'yii\grid\GridViewAsset' => [
'sourcePath' => '#webroot/js',
'basePath' => '#webroot/js',
'baseUrl' => 'vendor/js',
],
],
],
This was you are not modifying anything in the vendor folder.
The reply allowed html style with inline button but unfortunately it is not possible to use markdown style with inline button.
const inlineButtons = () => {
const inlineLinks = [
{
title: 'Google',
link: 'https://www.google.com/',
},
{
title: 'DuckDuckGo.com',
link: 'https://www.duckduckgo.com/',
},
];
const buttonLinks = inlineLinks.map(({ title, link }) =>
Markup.markdown().urlButton(title, link),
);
return Extra.markup(m => m.inlineKeyboard(buttonLinks, { columns: 1 }));
};
// Reply message
ctx.reply(
`<b>show_inline</b> *${show_inline}*`,
show_inline ? inlineButtons()
);
With the current code there is no style with in the message
There's Extra.markdown() and Extra.HTML()
Both ctx.reply() and ctx.replyWithHTML() works, the key point is the Extra.< Something >.markup
Try not mix replyWithHTML() with Extra.markdown() // Doesn't make sense
ANS:
ctx.replyWithHTML(
"<b>show_inline</b>",
Extra.HTML().markup(m =>
m.inlineKeyboard([
m.callbackButton("Single", "single"),
m.callbackButton("Range", "range")
])
)
);
Got my idea from https://github.com/telegraf/telegraf/issues/443
Edit:
For markdown, a single _ is invalid
<b>show_inline\</b> *${show_inline}*
Use Escape \\:
<b>show\\_inline</b> *${show_inline}*
Markup doesn't have a function called markdown()
(I use TS to check the functions they have)
I don't think you can style the inline keyboard text
I need to use a wysiwyg editor on my website.
I use symfony 4.
I've tried to use ckeditor 5 CDN (https://ckeditor.com/ckeditor-5/download/)
The view works well but the symfony form is not submitted. (the textareatype may kills the form because with ckeditor it is changed into many divs and the textarea section may be considered blank)
this is the code of the textarea which is in the form.
->add('content', TextareaType::class, [
'label' => "Content label",
'required' => true,
'attr' => [
'class' => "ckeditor"
]
])
and the code of the script
<script>
ClassicEditor
.create( document.querySelector( '.ckeditor' ) )
.catch( error => {
console.error( error );
} );
</script>
Thanks. it's hopeless how it's difficult to use a simple wysiwyg editor ..
I found the solution.
I emphasize that i use CKEditor 5.
ClassicEditor
.create( document.querySelector( '.ckeditor' ) )
.then( editor => {
theEditor = editor;
} )
.catch( error => {
console.error( error );
} );
document.getElementById("news_submit").addEventListener("click", function() {
theEditor.updateSourceElement();
});
the method is now "updateSourceElement" with CKEditor 5.
edit: this answer is for ckeditor 4 not for 5
ckeditor not update field in real time. You need to call updateElement ckeditor function before submit your form.
See: https://ckeditor.com/docs/ckeditor4/latest/api/CKEDITOR_editor.html#method-updateElement
I am having a hard time with antd's form.
I have this select field in this form and I want to get the value from it onChange but somehow not getting it to work properly.
say this is the item for which I want the values
<FormItem
{...formItemLayout}
label={fieldLabels.qcategoryid}
validateStatus={categoryError ? "error" : ""}
help={categoryError || ""}
>
{getFieldDecorator("qcategoryid", {
rules: [{ required: true, message: "Please select Category!" }],
onChange: this.handleCategoryChange
})(<Select>{categoryOptions}</Select>)}
</FormItem>
this is the categoryOptions
if (this.props.categories) {
categoryOptions = this.props.categories.map(item => (
<Select.Option
key={item.categoryid}
value={item.categoryid}
name={item.categoryname}
>
{item.categoryname}
</Select.Option>
));
}
I want both the name of the category and the id
so I created a handleCategoryChange which gets called onChange
and I am able to get the fields I want.
But, it seems that now, I have to click twice on the field to properly select it.
If I click it just once then it does show up in the console. but the field on the form still remains empty. when I click it again, then the field shows up in the form too.
So, what am I doing wrong here.
Ah,yes! Here's the handleCategoryChange function
handleCategoryChange = (value, e) => {
console.log("value is : ", value);
console.log("e : ", e);
this.props.form.setFieldsValue({ qcategoryid: value });
this.setState({
categorySelected: value,
categoryname: e.props.name
});
};
Just to make myself clear.
I need those values before I click submit.
not on submit.
maybe this will help Ant Design form API as of 22nd of May 2022
This was added in v4.20
const Demo = () => {
const [form] = Form.useForm();
const userName = Form.useWatch('username', form);
const { data: options } = useSWR(`/api/user/${userName}`, fetcher);
return (
<Form form={form}>
<Form.Item name="username">
<AutoComplete options={options} />
</Form.Item>
</Form>
);
};
I realize this is super late, but I think this might be what OP was looking for:
https://github.com/react-component/form/blob/3b9959b57ab30b41d8890ff30c79a7e7c383cad3/examples/server-validate.js#L74-L79
To set fields on a form dynamically, e.g. in a child via a callback, you could use
this.props.form.setFields({
user: {
value: values.user,
errors: [new Error('forbid ha')],
},
});
in a parent defined handleSelect method you called from the child on a selected value. you can alternatively use setFieldsValue if you dont want to pass an error field
Try this:
<FormItem
{...formItemLayout}
label={fieldLabels.qcategoryid}
validateStatus={categoryError ? "error" : ""}
help={categoryError || ""}
>
{getFieldDecorator("qcategoryid", {
rules: [{ required: true, message: "Please select Category!" }]
})(<Select onChange={this.handleCategoryChange}>{categoryOptions}</Select>)}
</FormItem>
And on the handleCategoryChange function
handleCategoryChange = (value, e) => {
this.setState({
categorySelected: value,
categoryname: e.props.name
});
};
Basically, changing the onChange from the getFieldDecorator helper to the Select, so it doesn't mess with antd's natural behavior, but gets the value and change on state
I've based this answer on the code to the registration form on their website. Specifically, the handleWebsiteChange function
https://ant.design/components/form/#components-form-demo-register
I have made a helper function to solve this problem, you have to pass the field
name you want to take out from the form and the form object.
const getFieldValue = (fieldName,form) => {
return Form.useWatch(fieldName,form);
}
console.log(getFieldValue("username"))
in above example I had to console updated username value.
demo
A quick response, and hopefully a quick solution. Rather than using onChange you may want to use onSelect/onDeselect handlers, per the documentation (https://ant.design/components/select/):
<Select onSelect={handleCategoryChange} .../>
I have found also that SELECT and other input components, due to their custom html nature operate differently, and so in my forms, I have often created them as dummy fields that are using to alter text/hidden inputs in order to achieve the desired behaviours in complex forms.
Either I am doing something wrong, or the ANT way is mildly annoying.
Hope this helps.
I have an MVC ListBoxFor control that I'm trying to bind data to and update using a Kendo MultiSelectFor.
The idea being that there is a list of users in the ListBox, and a list of available users in the MultiSelect box. When users are selected from the MultiSelect box and the add button clicked, an Ajax call is made to an action that updates the users list server side (through various API calls, which all work fine) and client side JavaScript is used to update the users and available users array object and the binding keeps the controls up to date with the updated lists.
I wish I could pin this down to just one issue, but honestly every time I try something I come up with different errors, so I'll just go with the latest iteration.
Model:
public IEnumerable<UserInformation> Users { get; set; }
public IEnumerable<UserInformation> AvailableUsers { get; set; }
JavaScript ViewModel:
var viewModel = kendo.observable({
availableUsersSelected: [],
users: #(Html.Raw(Json.Encode(this.Model.Users))),
availableUsers: #(Html.Raw(JsonConvert.SerializeObject(this.Model.AvailableUsers))),
moveToUsers: function () {
this.availableUsersSelected = this.get('availableUsersSelected');
this.users.push(this.availableUsers);
if (this.availableUsersSelected.length > 0) {
var formAction = '#Url.Combine(Url.Content("~/"), ControllerActions.Groups.GroupDefault, ControllerActions.Groups.AddUser)';
$.ajax({
url: formAction,
type: 'POST',
data: {
model: JSON.stringify(
{
groupId: $('#GroupId').val(),
users: this.availableUsersSelected
}
)
},
success: function (result) {
if (result) {
this.users.remove(this.availableUsersSelected);
}
}
});
}
}
});
MultiSelectFor control
#(Html.Kendo()
.MultiSelectFor(u => u.AvailableUsers)
.Placeholder("Please select")
.BindTo(new SelectList(Model.AvailableUsers, "Id", "Name"))
.HtmlAttributes(new { data_bind = "value: availableUsersSelected" })
)
ListBox control
#(Html.EditorLine(Language.Fields.Users, Html.ListBoxFor(u => u.Users, new SelectList(Model.Users, "Id", "Name"), new { #class = "form-control", data_bind = "source: users", data_value_field ="Id", data_text_field = "Name" })))
Add control
<img src="~/Content/images/up-arrow.jpg" alt="Move to users" width="30" data-bind="events: {click: moveToUsers}" />
To reiterate, the Ajax call and updating server side all work fine, it's the client side control binding that I'm struggling to understand.
The errors I'm getting are 1) a syntax error with the comma on this line users: #(Html.Raw(Json.Encode(this.Model.Users))), and the line after it (same thing, effectively), and 2) a "ReferenceError: Id is not defined" on the moveToUsers function call when the add button is pressed.
(I can honestly say that the amount of frustration I'm experiencing with this is driving me insane, so sorry if it came across in the question)
So after calming down a bit, reading a few more bits of the documentation about data binding and observable arrays, I realised I was making a few fundamental errors.
JavaScript ViewModel:
var viewModel = {
availableUsersSelected: new kendo.data.ObservableArray([]),
users: new kendo.data.ObservableArray(#(Html.Raw(Json.Encode(this.Model.Users)))),
availableUsers: new kendo.data.ObservableArray(#(Html.Raw(Json.Encode(this.Model.AvailableUsers)))),
moveToUsers: function () {
if (viewModel.availableUsersSelected.length > 0) {
var formAction = '#Url.Combine(Url.Content("~/"), ControllerActions.Groups.GroupDefault, ControllerActions.Groups.AddUser)';
$.ajax({
url: formAction,
type: 'POST',
data: {
model: JSON.stringify(
{
groupId: $('#GroupId').val(),
users: viewModel.availableUsersSelected
}
)
},
success: function (result) {
if (result) {
removeFromAvailableUsers();
}
else
alert('add failed!');
},
failure: function () {
alert('ajax failed!');
}
});
}
}
};
function removeFromAvailableUsers() {
for (var i = 0; i < viewModel.availableUsersSelected.length; ++i) {
viewModel.users.push(viewModel.availableUsersSelected[i]);
viewModel.availableUsers.remove(viewModel.availableUsersSelected[i]);
}
var ele = $('#AvailableUsers').data("kendoMultiSelect");
ele.value("");
ele.input.blur();
};
The main differences are instead of declaring the entire object as a kendo observable are declaring each array as an observable array, then referencing them through the viewModel object instead of assuming that the "this" scope will encapsulate them.
Then, as D_Learning mentioned in the comments above, I was unnecessarily using two bindings for the MultiSelect control, so that then became:
#(Html.Kendo()
.MultiSelectFor(u => u.AvailableUsers)
.Placeholder("Please select")
.HtmlAttributes(new { data_bind = "source: availableUsers, value: availableUsersSelected", data_value_field = "Id", data_text_field = "Name" })
)
(Notice no ".BindTo" property)
Aside from that, the MVC side of things stayed the same and it all words perfectly.
If you wish to remove or add data to the Kendo Multiselect then you will need to add them via the DataSource as:
$("#AvailableUsers").data("kendoMultiSelect").dataSource.add({"text": "new Item", "value": 1000});
For more detail about Adding or removing Items to Multiselect (Kendo DataSrouce) see: Kendo DataSource Adding Removing Items
Similarly you can remove the item from the Listbox as below:
var selectedIndex = ListBox1.selectedIndex();
clearSelection();
if (selectedIndex != -1) {
ListBox1.options.remove(selectedIndex);
For more detail about Adding or removing Items from HTML Listbox see: HTML Listbox Items Manipulation.
Please let me know if you have any error after this.