How to create an input field with a label in Observablehq - observablehq

I can create an input text box with this code. What is the best way to add a label to it on the same line, while still binding it to the same global variable?
viewof myText = html`<input type="text" value="initial value">
I would like
viewof myText = html`Enter something: <input type="text" value="initial value">
but myText doesn't bind to the input field.

The simplest way to get this effect is to use Jeremy's Inputs notebook, which includes labeled text boxes. You can import just the textbox method into your notebook, and that fixes the general issue.
Without importing another notebook, the simplest method is this:
viewof myText = {
let form = html`Enter something: <input type="text" value="initial value">`;
form.addEventListener('input', e => {
form.value = e.target.value
});
return form;
}
viewof reads the .value property of what's returned to it, and this code sets the .value property to the value of the contained input. When an input element is the only thing in a cell, viewof works without any extra code, but if there are multiple elements that all have values, user code needs to tell the notebook which input provides the value.

Currently (October 2021) Observable Inputs are the preferred way of adding input elements to notebooks. See the introductory notebook and collection
viewof myText = Inputs.text({
label: "Enter something",
placeholder: "Text",
value: "Initial value"
})

Related

React bootstrap typeahead clearButton icon (X) does not appear for a single selection

I have tried selecting clearButton prop for a single selection input. However it does not work as expected. The clear (x) icon does not appear with a default selected input. It appears only once there is an event change, that is if I select some other input. My problem is that removing the input manually does not trigger a change in the selected value. Any pointers would be appreciated.
<Typeahead
clearButton
defaultInputValue={props.city}
options={props.cityOptions}
onChange={(selected) => handleCityFieldChange(selected[0], props)}
placeholder="Choose a city"
/>
Here's the handleCityFieldChange function:
handleCityFieldChange = (selected, props) => {
const newFieldValues = Object.assign({}, props.fieldValues, {"city": selected});
props.onChange(newFieldValues);
};
Use defaultSelected, not defaultInputValue:
<Typeahead
clearButton
defaultSelected={props.city}
options={props.cityOptions}
onChange={(selected) => handleCityFieldChange(selected[0], props)}
placeholder="Choose a city"
/>
The clear button only appears when there is a selection. defaultInputValue sets the value of the input, without actually selecting an option, which is why you weren't seeing the button.
Note: defaultSelected expects an array, so if props.city is an object, you'll need to pass [props.city].

How do I bind a value to a textbox in Angular2?

I have been trying to figure out how to bind a value to a textbox in Angular2. Currently I have a textbox with a placeholder that is loaded with a predetermined value.
<input id="textbox" class="k-textbox" placeholder={{label}} />
But once I change a value of a date component, I would want the placeholder value to be updated to the date value selected. So far i wrote this but this doesn't seem to be working. Please advice.
date-component.html
<input id="datepicker" (input)="changeLabel()"/>
date-component.ts
label:string;
constructor() {
this.label = 'Select Date';
}
changeLabel() {
this.label = 'Date Selected';
}
}
use an click event to propagate the changes.
date-component.html
<input id="datepicker" (click)="changeLabel()"/> //<-- click event
You could use two way databinding with NgModel.
https://angular.io/docs/ts/latest/guide/template-syntax.html#!#ngModel
Basically this would make "label" change to whatever the user types.
<input [(ngModel)]="label" id="datepicker" />
You will also need to import FormsModule in your app.
Plunker to show what I mean:
https://plnkr.co/edit/CfmalT7GesrP5lzBsNFx?p=preview
use keyup Event
<input (keyup)="changeLabel()">
enter the value its call the keyup event

Adding Bootstrap 3 popover breaks JQuery Validation Plugin

I have a form, which I'm validating using JQuery Validation plugin. Validation works file until I add a Bootstrap 3 popover to the text field with name "taskName" (the one being validated) (please see below) . When I add the popover to this text field, error messages are repeatedly displayed every time the validation gets triggered. Please see the code excerpts and screenshots below.
I've been trying to figure out what is happening, with no success so far. Any help will be greatly appreciated. Thanks in advance!
HTLM Excerpt
The popover content
<div id="namePopoverContent" class="hide">
<ul>
<li><small>Valid characters: [a-zA-Z0-9\-_\s].</small></li>
<li><small>Required at least 3 characters.</small></li>
</ul>
</div>
The form
<form class="form-horizontal" role="form" method="post" action="" id="aForm">
<div class="form-group has-feedback">
<label for="taskName" class="col-md-1 control-label">Name</label>
<div class="col-md-7">
<input type="text" class="form-control taskNameValidation" id="taskName" name="taskName" placeholder="..." required autocomplete="off" data-toggle="popover">
<span class="form-control-feedback glyphicon" aria-hidden="true"></span>
</div>
</div>
...
</form>
JQuery Validate plugin setup
$(function() {
//Overwriting a few defaults
$.validator.setDefaults({
errorElement: 'span',
errorClass: 'text-danger',
ignore: ':hidden:not(.chosen-select)',
errorPlacement: function (error, element) {
if (element.is('select'))
error.insertAfter(element.siblings(".chosen-container"));
else
error.insertAfter(element);
}
});
//rules and messages objects
$("#aForm").validate({
highlight: function(element) {
$(element).closest('.form-group').removeClass('has-success').addClass('has-error');
$(element).parent().find('.form-control-feedback').removeClass('glyphicon-ok').addClass('glyphicon-remove');
},
success: function(element) {
$(element).closest('.form-group').removeClass('has-error').addClass('has-success');
$(element).parent().find('.form-control-feedback').removeClass('glyphicon-remove').addClass('glyphicon-ok');
}
});
$('.taskNameValidation').each(function() {
$(this).rules('add', {
required: true,
alphanumeric: true,
messages: {
required: "Provide a space-separated name."
}
});
});
});
Bootstrap 3 popover setup
$('[data-toggle="popover"]').popover({
trigger: "focus hover",
container: "body",
html: true,
title: "Name Tips",
content: function() { return $('#namePopoverContent').html();}
});
The screenshots
First Edit
It seems I did not make my question clear, so here it goes my first edit.
I'm not using the popover to display the error messages of the validation. The error messages are inserted after each of the fields that fail validation, which is precisely what I want. Hence, this question does not seem to be a duplicate of any other question previously asked.
Regarding the popover, I just want to add an informative popover that gets displayed whenever the user either clicks the text field "taskName" or hovers the mouse over it. Its role is completely independent of the validation.
The question is, then, why adding the (independent) popover is making the validation plugin misbehave, as shown in the screenshots.
I had the very same issue a few days ago and the only solution I found was to use 'label' as my errorElement:.
Change the line errorElement: 'span' to errorElement: 'label' or simply removing the entire line will temporarily fix the issue. ('label' is the default. )
I am not completely sure what the JQ validate + BS popover conflict is, but I will continue to debug.
After some debugging I think I found the issue.
Both jQuery validate and bootstrap 3 popovers are using the aria-describedby attribute. However, the popover code is overwriting the value written by jQuery validate into that attribute.
Example: You have a form input with an id = "name", jQuery validate adds an aria-describedby = "name-error" attribute to the input and creates an error message element with id = "name-error" when that input is invalid.
using errorElement:'label' or omitting this line works because on line 825 of jquery.validate.js, label is hard-coded as a default error element selector.
There are two ways to fix this issue:
Replace all aria-describedby attributes with another attribute name like data-describedby. There are 4 references in jquery.validate.js. Tested.
or
Add the following code after line 825 in jquery.validate.js. Tested.
if ( this.settings.errorElement != 'label' ) {
selector = selector + ", #" + name.replace( /\s+/g, ", #" ) + '-error';
}
I will also inform the jQuery validate developers.
The success option should only be used when you need to show the error label element on a "valid" element, not for toggling the classes.
You should use unhighlight to "undo" whatever was done by highlight.
highlight: function(element) {
$(element).closest('.form-group').removeClass('has-success').addClass('has-error');
$(element).parent().find('.form-control-feedback').removeClass('glyphicon-ok').addClass('glyphicon-remove');
},
unhighlight: function(element) {
$(element).closest('.form-group').removeClass('has-error').addClass('has-success');
$(element).parent().find('.form-control-feedback').removeClass('glyphicon-remove').addClass('glyphicon-ok');
}
(The success option could also be used in conjunction with the errorPlacement option to show/hide tooltips or popovers, just not to do the styling, which is best left to highlight and unhighlight.)
Also, I recommend letting the Validate plugin create/show/hide the error label element, rather than putting it the markup yourself. Otherwise, the plugin will create its own and ignore the one you've created.
In case you were unaware, you cannot use the alphanumeric rule without including the additional-methods.js file.

knockout.js - help dealing with UI state changes when polling for updates

I'm having a problem losing UI state changes after my observables change and was hoping for some suggestions.
First off, I'm polling my server for updates. Those messages are in my view model and the <ul> renders perfectly:
When my user clicks the "reply" or "assign to" buttons, I'm displaying a little form to perform those actions:
My problem at this point was that when my next polling call returned, the list re-binds and I lose the state of where the form should be open at. I went through adding view model properties for "currentQuestionID" so I could use a visible: binding and redisplay the form after binding.
Once that was complete, the form displays properly on the "current item" after rebinding but the form values are lost. That is to say, it rebinds, rebuilds the form elements, shows them, but any user input disappears (which of course makes sense since the HTML was just regenerated).
I attempted to follow the same pattern (using a value: binding to set the value and an event: {change: responseChanged} binding to update an observable with the values). The HTML fragment looks like this:
<form action="#" class="tb-reply-form" data-bind="visible: $root.showMenu($data, 'reply')">
<textarea id="tb-response" data-bind="value: $root.currentResponse, event: {keyup: $root.responseChanged}"></textarea>
<input type="button" id="tb-submitResponse" data-bind="click: $root.submitResponse, clickBubble: false" value="Send" />
</form>
<form action="#" class="tb-assign-form" data-bind="visible: $root.showMenu($data, 'assign')">
<select id="tb-assign" class="tb-assign" data-bind="value: $root.currentAssignee, options: $root.mediators, optionsText: 'full_name', optionsValue: 'access_token', optionsCaption: 'Select one...', event: {change: $root.assigneeChanged}">
</select>
<input type="button" id="tb-submitAssignment" data-bind="click: $root.submitAssignment, clickBubble: false" value="Assign"/>
</form>
Now, I end up with what seems like an infinite loop where setting the value causes change to happen, which in turn causes value... etc.
I thought "screw it" just move it out of the foreach... By moving the form outside of each <li> in the foreach: binding and doing a little DOM manipulation to move the form into the "current item", I figured I wouldn't lose user inputs.
replyForm.appendTo(theContainer).show();
It works up until the first poll return & rebind. Since the HTML is regenerated for the <ul>, the DOM no longer has my form and my attempt to grab it and do the .appendTo(container) does nothing. I suppose here, I might be able to copy the element into the active item instead of moving it?
So, this all seems like I'm missing something basic because someone has to have put a form into a foreach loop in knockout!
Does anybody have a strategy for maintaining form state inside a bound item in knockout?
Or, possibly, is there a way to make knockout NOT bind anything that's already bound and only generate "new" elements.
Finally, should I just scrap knockout for this and manually generate for "new items" myself when each polling call returns.
Just one last bit of info; if I set my polling interval to something like 30 seconds, all the bits "work" in that it submits, saves, rebinds, etc. I just need the form and it's contents to live through the rebinding.
Thanks a ton for any help!
Well, I figured it out on my own. And it's embarrassing.
Here is a partial bit of my VM code:
function TalkbackViewModel( id ) {
var self = this;
talkback.state.currentTalkbackId = "";
talkback.state.currentAction = "";
talkback.state.currentResponse = "";
talkback.state.currentAssignee = "";
self.talkbackQueue = ko.observableArray([]);
self.completeQueue = ko.observableArray([]);
self.mediators = ko.observableArray([]);
self.currentTalkbackId = ko.observable(talkback.state.currentTalkbackId);
self.currentAction = ko.observable(talkback.state.currentAction);
self.currentResponse = ko.observable(talkback.state.currentResponse);
self.currentAssignee = ko.observable(talkback.state.currentAssignee);
self.showActionForm = function(data, action) {
return ko.computed(function() {
var sameAction = (self.currentAction() == action);
var sameItem = (self.currentTalkbackId() == data.talkback_id());
return (sameAction && sameItem);
}, this);
};
self.replyToggle = function(model, event) {
// we're switching from one item to another. clear input values.
if (self.currentTalkbackId() != model.talkback_id() || self.currentAction() != "reply") {
self.currentResponse("");
self.currentAssignee("");
self.currentTalkbackId(model.talkback_id());
}
My first mistake was trying to treat the textarea & dropdown the same. I noticed the dropdown was saving value & reloading but stupidly tried to keep the code the same as the textarea and caused my own issue.
So...
First off, I went back to the using the $root view model properties for currentAssignee and currentResponse to store the values off and rebind using value: bindings on those controls.
Next, I needed to remove the event handlers:
event: { change: xxxChanged }
because they don't make sense (two way binding!!!!). The drop down value changes and updates automatically by using the value: binding.
The textarea ONLY updated on blur, causing me to think I needed onkeyup,onkeydown, etc. I got rid of those handlers because they were 1) wrong, 2) screwing up the value: binding creating an infinite loop.
I only needed this on the textarea to get up-to-date value updates to my viewmodel property:
valueUpdate: 'input'
At this point everything saves off & rebinds and I didn't lose my values but my caret position was incorrect in the textarea. I added a little code to handle that:
var item = element.find(".tb-assign");
var oldValue = item.val();
item.val('');
item.focus().val(oldValue);
Some browsers behave OK if you just do item.focus().val(item.val()); but i needed to actually cause the value to "change" in my case to get the caret at the end so I saved the value, cleared it, then restored it. I did this in the event handler for when the event data is returned to the browser:
$(window).on("talkback.retrieved", function(event, talkback_queue, complete_queue) {
var open_mappings = ko.mapping.fromJS(talkback_queue);
self.talkbackQueue(open_mappings);
if (talkback_queue) self.queueLength(talkback_queue.length);
var completed_mappings = ko.mapping.fromJS(complete_queue);
self.completeQueue(completed_mappings);
if (self.currentTalkbackId()) {
var element = $("li[talkbackId='" + self.currentTalkbackId() + "']");
if (talkback.state.currentAction == "assign") {
var item = element.find(".tb-assign");
var oldValue = item.val();
item.val('');
item.focus().val(oldValue);
} else {
var item = element.find(".tb-response");
var oldValue = item.val();
item.val('');
item.focus().val(oldValue);
}
}
}
);
So, my final issue is that if I used my observables in my method "clearing" the values when a new "current item" is selected (replyToggle & assignToggle), they don't seem to work.
self.currentResponse("");
self.currentAssignee("");
I cannot get the values to clear. I had to do some hack-fu and added the line below that to just work around it for now:
$(".tb-assign").val("");

Form validation using angular

i have a basic form . inside it , i have two fields(dropdown and textbox) whose behaviour is dependent on each other. I want to reset the textbox based on the change in dropdown. Also i want to add/integrate into the DOM as a new element so that validity etc can be taken care of which is to say i can use my $dirty to hide/show the message .
Use ng-model and $watch
<select ng-model="dropdown" ng-options="**"><!-- --></select>
<textbox ng-model="textbox"></textbox>
$scope.$watch('dropdown', function () {
$scope.textbox = '';
});
http://docs.angularjs.org/api/ng.$rootScope.Scope#$watch
Two things:
To have one value be dependant on another, just listen to the ng-change event of the first and then update the variable that the second one is bound to. eg:
$scope.selectChanged = function() {
$scope.textValue = '';
}
To do validation, one approach I like to take is to have an "error" element declared and just show/hide it when needed.
Here's a quick snippet that illustrates both approaches
http://jsfiddle.net/marplesoft/ULhVS/