I am able to get the autocompletion list on (ctrl+space) key event in ace editor but I want to achieve the same behavior on user key event. Is there any way to do the same?
For adding custom autocomplete you need to bind the key, with addCommand, and then call the auto-complete
editor.commands.addCommand({
name: "myCommand",
bindKey: { win: "$", mac: "$" },
exec: function (editor) {
autocomplete();
}
});
Once the user trigger's the key you can call your autocomplete function, I'm adding a sample autocomplete function here, make the changes as you require.
autocomplete: function () {
staticWordCompleter = {
var getWordList = function(editor, session, pos, prefix, callback, isRHSEditor) {
var wordList = ["Java","Javascript","Python"]; // add your words to this list
callback(null, wordList.map(function(word) {
return {
caption: word,
value: word
};
}));
editor.completers = [staticWordCompleter];
}
To always use autocomplete you can try this:
editor.commands.on("afterExec", function (e) {
if (e.command.name == "insertstring" && /^[\w.]$/.test(e.args)) {
editor.execCommand("startAutocomplete");
}
});
Or you can bind the change event and call the autocomplete, which would trigger the autocomplete on each click
editor.on("change", function () {
autocomplete();
});
Related
I added an Autocomplete feature to a form on a HTML template, i would like to perform some actions when an hint is selected, is there any way to do it? I'm using Jquery-Typeahead. Here is my actual code:
$(document).ready(function(){
// Defining the local dataset
$.getJSON('http://127.0.0.1:8000/myapi', function(data) {
console.log(data)
var dt = data
$(() => {
$('#myform').typeahead({
source: {
data: dt.results.map(record => record.item)
},
callback: {
onInit: function($el) {
console.log(`Typeahead initiated on: ${$el.prop('tagName')}#${$el.attr('id')}`);
},
onClick: function() {
console.log(); //How can i console.log() the selected value here, for example?
}
}
});
});
});
});
Try defining an onClickAfter callback, it's called right after user clicks on an item. Something like this:
onClickAfter: function(node, a, item, event) {
// item will be the item you selected
console.log(item);
}
You can also define the onClickBefore callback the same way, and it will be called immediately before "normal" typeahead behaviour kicks in
I have a combo box and I want to throw a message with a fallback logic, in case he selects something, he should get a warning, if he presses okay it executes the logic, if he does not it should be canceled.
<ComboBox id="id1" change="onChange">
<core:Item id="id2" text="A"></core:Item>
<core:Item id="id3" text="B"></core:Item>
<core:Item id="id4" text="C"></core:Item>
</ComboBox>
then I have my messagebox in the onChange function:
onChange: function (oEvent) {
sap.m.MessageBox.show("Are you sure you want to do that?", {
icon: sap.m.MessageBox.Icon.Information,
title: "Info",
actions: [sap.m.MessageBox.Action.YES, sap.m.MessageBox.Action.NO],
defaultAction: sap.m.MessageBox.Action.NO,
onClose: function (sButton) {
if (sButton === sap.m.MessageBox.Action.YES) {
//execute my logic in here => that works
} else {
oEvent.stopPropagation(); //I tried this but this does not work
}
}
});
}
how can I achieve that?
In other words, all I would actually need is to know what the predecessor selection of that combobox was.
I did not find out how to get that out of the oEvent.
the approach is correct (the dialog inside the onChange) but you need some changes.
When SAPUI5 call the onChange method the value is already written inside your control so the oEvent.stopPropagation(); is doing nothing at all.
What you could do is to use the ComboBox method setSelectedItem(null) that should reset the current selection (reverting the user choice).
UPDATE: I've updated the code in order to solve your request.
__selectedItem: null,
onChange: function (oEvent) {
var that = this;
var source = oEvent.getSource();
var selectedItem = oEvent.getSource().getSelectedItem();
MessageBox.show("Are you sure you want to do that?", {
icon: MessageBox.Icon.Information,
title: "Info",
actions: [MessageBox.Action.YES, MessageBox.Action.NO],
defaultAction: MessageBox.Action.NO,
onClose: function (sButton) {
if (sButton === MessageBox.Action.YES) {
//execute my logic in here => that works
that.__selectedItem = selectedItem;
} else {
source.setSelectedItem( that.__selectedItem );
}
}
});
}
Looking at the SAP code on GitHub in InputBase.js, the new value is already written into the property when the event you attach to is fired. My proposal would be saving the selected value in a class variable inside your controller and reverting to this value once the user cancels to achieve your goal.
I decided to go for the following solution, thanks anyway for all the other approaches
onChange: function (oEvent) {
var source = oEvent.getSource();
MessageBox.show("Are you sure you want to do that?", {
icon: MessageBox.Icon.Information,
title: "Info",
actions: [MessageBox.Action.YES, MessageBox.Action.NO],
defaultAction: MessageBox.Action.NO,
onClose: function (sButton) {
if (sButton === MessageBox.Action.YES) {
//execute my logic in here => that works
} else {
var oldSelection = oModel.getProperty(oSource.getBindingContext().getPath() + "/PropertyPath");
switch (oldSelection) {
case "A":
oSource.setSelectedItem(oSource.getItems()[0], true, true);
break;
case "B":
oSource.setSelectedItem(oSource.getItems()[1], true, true);
break;
case "C":
oSource.setSelectedItem(oSource.getItems()[3], true, true);
break;
}
}
}
});
}
I have an MVC Control for a KendoUI ComboBox that does NOT setup the Change Event ahead of time. Upon rendering, a page controller sets-up & shims-in its' own Change Event.
Oddly, this event gets called TWICE:
When I change the Selected Item
When I click away from the control
Q: What am I doing wrong?
Q: Is this HOW we should over-write the change event on an existing Kendo ComboBox?
MVC CONTROL:
As you can see, I am NOT defining any client-side events here...
#(Html.Kendo().ComboBox()
.Name("ddlTechnician")
.Filter("contains")
.Placeholder("Select Technician...")
.DataTextField("Text")
.DataValueField("Value")
.BindTo(new List<SelectListItem>() {
new SelectListItem() { Text = "Frank", Value = "1" },
new SelectListItem() { Text = "Suzie", Value = "2" },
new SelectListItem() { Text = "Ralph", Value = "3" }
})
.Suggest(true)
.HtmlAttributes(new { style = "width:300px;" }))
PAGE CONTROLLER:
And, I am only defining the event ONCE here. I have also confirmed the event isn't already firing BEFORE setting it in the Page Controller
$(document).ready(function () {
var PageController = (function ($) {
function PageController(options) {
var that = this,
empty = {},
dictionary = {
elements: {
form: null
},
instances: {
ddlTechnician: null
},
selectors: {
form: 'form',
ddlTechnician: '#ddlTechnician'
}
};
var initialize = function (options) {
that.settings = $.extend(empty, $.isPlainObject(options) ? options : empty);
dictionary.elements.form = $(dictionary.selectors.form);
// Objects
dictionary.instances.ddlTechnician = $(dictionary.selectors.ddlTechnician, dictionary.elements.form).data('kendoComboBox');
// Events
dictionary.instances.ddlTechnician.setOptions({ change: that.on.change.kendoComboBox });
};
this.settings = null;
this.on = {
change: {
kendoComboBox: function (e) {
// This is getting called MULTIPLE TIMES
console.log('kendoComboBox RAN');
}
}
}
};
initialize(options);
}
return PageController;
})(jQuery);
var pageController = new PageController({});
});
I was able to reproduce your problem on a Kendo JQuery Combobox when I set the event handler through setOptions, which is not the recommended way after the widget has been rendered. Instead you should use the "bind" method as shown in the documentation's example for change events.
Try changing the line of code where you set your event handler to this:
dictionary.instances.ddlTechnician.bind("change", that.on.change.kendoComboBox);
Here's a dojo that shows the difference: http://dojo.telerik.com/iyEQe
Hope this helps.
I have a CKEDITOR plugin that I'm having trouble disabling when there is no selected copy in the editor. Right now, the user can click the button without any highlighted text in the editor. I would like to modify it so that the plugin button is only active when there is copy highlighted in the editor. I've followed the suggestion here, but it isn't working.
Main Plugin Code:
CKEDITOR.plugins.add('cta', {
icons: 'cta',
init: function (editor) {
// Funciton depending on editor selection (taken from the scope) will set the state of our command.
function RefreshState() {
console.log('RefreshState');
var editable = editor.editable(),
// Command that we want to control.
command = editor.getCommand('source'),
range,
commandState;
if (!editable) {
// It might be a case that editable is not yet ready.
console.log("editable not ready yet");
return;
}
// We assume only one range.
range = editable.getDocument().getSelection().getRanges()[0];
console.log(`range: `);
console.log(range);
// The state we're about to set for the command.
commandState = (range && !range.collapsed) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED;
console.log('commandState');
console.log(commandState);
command.setState(commandState);
}
// We'll use throttled function calls, because this event can be fired very, very frequently.
var throttledFunction = CKEDITOR.tools.eventsBuffer(250, RefreshState);
// Now this is the event that detects all the selection changes.
editor.on('selectionCheck', throttledFunction.input);
// You'll most likely also want to execute this function as soon as editor is ready.
editor.on('instanceReady', function (evt) {
// Also do state refresh on instanceReady.
RefreshState();
});
editor.addCommand('ctabtn', new CKEDITOR.dialogCommand('ctaDialog'));
editor.ui.addButton('cta', {
label: 'Insert Call to Action button',
command: 'ctabtn',
toolbar: 'insert'
});
CKEDITOR.dialog.add('ctaDialog', this.path + 'dialogs/cta.js');
}
});
My dialog code is here:
CKEDITOR.dialog.add('ctaDialog', function (editor) {
return {
// Basic properties of the dialog window: title, minimum size.
title: 'Call to Action',
minWidth: 400,
minHeight: 200,
// Dialog window content definition.
contents: [{
// Definition of the Basic Settings dialog tab (page).
id: 'tab-basic',
label: 'Basic Settings',
// The tab content.
elements: [{
// Text input field for the Call to Action text.
type: 'text',
id: 'cta',
label: 'Call to Action',
// Validation checking whether the field is not empty.
validate: CKEDITOR.dialog.validate.notEmpty("Call to Action field cannot be empty.")
},
{
// Text input field for the link text.
type: 'text',
id: 'url',
label: 'URL',
// Validation checking whether the field is not empty.
validate: CKEDITOR.dialog.validate.notEmpty("URL field cannot be empty.")
}
]
}],
// method invoked when the dialog button is clicked
onShow: function () {
var element = editor.getSelection();
var link = CKEDITOR.plugins.link;
var _this = this.getParentEditor();
var CTAhref = link.getSelectedLink(_this);
this.setValueOf('tab-basic', 'cta', element.getSelectedText().toString());
if (CTAhref != '' && CTAhref !== null) {
this.setValueOf('tab-basic', 'url', CTAhref.$.href);
}
},
// This method is invoked once a user clicks the OK button, confirming the dialog.
onOk: function () {
var dialog = this;
var CTA = editor.document.createElement('a');
CTA.setAttribute('href', dialog.getValueOf('tab-basic', 'url'));
CTA.setAttribute('class', 'btn btn-special--lg');
CTA.setText(dialog.getValueOf('tab-basic', 'cta'));
editor.insertElement(CTA);
}
};
});
Any ideas on why the plugin icon button on the toolbar doesn't become inactive when there is no copy highlighted in the editor? I can see in the console that CKEDITOR.dom.range.collapsed is toggling between TRUE/FALSE depending upon whether text is highlighted or not. It's just not disabling the button.
As stated, the suggested way of handling this was not working for me. What was working was using range.collapsed in returning a true value if a selection was made in the editor. With that, I turned to using Jquery to handle the rest.
// Hacky. But it gets the job done.
// a.cke_button.cke_button__cta.cke_button_off is the selector for my toolbar button.
// The onclick function listed was pulled from looking at the CKeditor functions
// to initiate my plugins modal.
// The setting of the "onclick" prop to null is needed to override the modal onclick
// binding when there is no selection.
range = editable.getDocument().getSelection().getRanges()[0];
if (range.collapsed === false) {
$('a.cke_button.cke_button__cta.cke_button_off').attr("onclick", 'CKEDITOR.tools.callFunction(83,this);return false;');
$('a.cke_button__cta').toggleClass('cta_button_disabled');
} else {
$('a.cke_button.cke_button__cta.cke_button_off').prop("onclick", null);
}
I've written a program that includes a form that the user interacts with. Because there are lots of events bound to different buttons I have written a loop that parses some JS that contains the form input information. Here is some example data:
var value = 0,
forms = {
place_controls : {
attrs : {
'class' : 'place-form'
},
input : {
place_x : {
attrs : {
type : 'text',
},
events : {
change : function () {
value = 10;
}
}
},
place_y : {
attrs : {
type : 'text',
},
events : {
change : function () {
value = 50
}
}
}
}
}
}
The data is then parsed by this:
$.each(forms, function (form_index, form) {
var $form_markup = $('<form>').attr(form.attrs);
// Next: loop through each input element of the form we've reached
$.each(form.input, function (element_index, element) {
var $elem = $('<input>').attr(element.attrs);
$elem.appendTo($form_markup);
if (element.events !== undefined) {
$.each(element.events, function (event_index, event) {
$elem.bind(event_index, event);
//$form_markup.on(event_index, $elem, event);
});
}
});
$form_markup.appendTo($form_goes_here);
});
As you can see, I'm using .bind() at the moment, however I want to use .on(). Unfortunately, when I do this all of the items within a form are bound to the last event parsed by the function. When I use .bind() everything works as planned - i.e. Clicking on 'place_x' sets value to 10, clicking 'place_y' sets value to 50.
When using .on(), whichever I change sets value to 50, which I am assuming is because the last function is becoming bound to each event.
Can anybody see what I have done wrong?
Update: There are many different ways to do this, and I have subsequently changed how my code works, however this question is related to why .bind() is working and why .on() is not.
//$elem.bind(event_index, event);
//It looks like you should just be using .on() like this
$elem.on(event_index, event);
The way it looks like you are trying to use .on() is in the live -bubbling- event sort of way, it looks like only the last event you are created is sticking, why each value just gets set to 50.
//$form_markup.on(event_index, $elem, event);
You can create elements with property maps that include handler functions in one simple call:
var $elem = $('<input/>', properties);
The "properties" object can contain event handlers:
var $elem = $('<input/>', {
type: 'text',
name: 'somethingUseful',
click: function(ev) { /* click handler */ },
change: function(ev) { /* change handler */ },
css: { color: "red" }
});