How to fix Angular bug requiring user to click a separate element before choosing a second mat chip - html

Here is the link for an example of the issue I will attempt to describe. In the chips autocomplete example, click the text box to select a new fruit.
Now, before clicking anywhere else, click again on the text box as you did before.
This should result in no options showing up. The issue here is that the user must either begin keying in a new selection or first click another element in the window before matchip will show the options to choose from. I am wondering if there is a way to fix this issue. I would like a user to be able to choose a selection from the list and then immediately click the text box as they had before and make a new selection.

I'm using mat-chip-list inside an outer *ngFor iterating over a FormArray.
Here is what I'have done. It's pretty efficient :
<input
#validatorInput
#operationTrigger="matAutocompleteTrigger"
[formControl]="contactCtrl"
[matAutocomplete]="auto"
[matChipInputFor]="chipList"
(blur)="contactCtrl.setValue(''); validatorInput.value='';"
(click)="contactCtrl.setValue(''); validatorInput.value=''; operationTrigger.openPanel()">
The trick is
Always clear your html input and your (shared) formControl with an empty and not null value each time the blur and click events occur.
Do NOT do this 'clear' on the input focus event. (Because when you delete the last chip, the input is auto-focus and you will have the famous Expression has changed after it was checked.
Call operationTrigger.openPanel(); when the user click on the input
Setting contactCtrl.setValue(''); allows your autocomplete panel to be automatically opened when you call operationTrigger.openPanel()
Setting validatorInput.value=''; is just a way to properly sync your formControl with the html input to ensure a good UX/UI behavior.
Inside my formArray, the formControl is the same for all the inputs but it does not matter since the user can only manipulate one input at a given time

Since you didn't post your code and you mention the example on the material site I'm going to do it as a fork of the stackblitz example they have on their site.
But this will allow you to open the autocomplete panel again despite having had the cursor there and choosing an option previously.
// Using MatAutocompleteTrigger will give you access to the API that will allow you to
// to open the panel or keep it open
...
#ViewChild(MatAutocompleteTrigger, {static: false}) trigger: MatAutocompleteTrigger;
...
ngAfterViewInit() {
fromEvent(this.fruitInput.nativeElement, 'click')
.pipe(
tap(() => {
this.trigger.openPanel()
})
).subscribe()
}
Link to the full stackblitz:
https://stackblitz.com/edit/angular-sb38ig

Related

How should I access generated children of a custom HTML component in an idiomatic React way?

I am attempting to create a search bar using a custom HTML component for predictive text input. The way this component is built, it generates several plain HTML children that I need to act on to get full features. Specifically, I need to execute a blur action on one of the generated elements when the user presses escape or enter.
I got it to work using a ref on the custom component and calling getElementsByClassName on the ref, but using getElementsByClassName does not seem like the best solution. It pierces through the virtual and has odd side effects when testing.
This is a snippet of the component being rendered:
<predictive-input id='header-search-bar-input' type='search'
value={this.state.keywords}
ref={(ref: any) => this.predictiveInput = ref}
onKeyDown={(e: React.KeyboardEvent<any>) => this.handleKeyDown(e)}>
</predictive-input>
and the keyDown handler:
private handleKeyDown(e: React.KeyboardEvent<any>) {
// must access the underlying input element of the kat-predictive-input
let input: HTMLElement = this.predictiveInput.getElementsByClassName('header-row-text value')[0] as HTMLElement;
if (e.key === 'Escape') {
// blur the predictive input when the user presses escape
input.blur();
} else if (e.key === 'Enter') {
// commit the search when user presses enter
input.blur();
// handles action of making actual search, using search bar contents
this.commitSearch();
}
}
The element renders two children, one for the bar itself and one for the predictive dropdown. The classes of the underlying in the first are 'header-row-text' and 'value', so the element is correctly selected, but I am worried that this is violating proper React style.
I am using React 16.2, so only callback refs are available. I would rather avoid upgrading, but if a 16.3+ solution is compelling enough, I could consider it.
If you don't have any control over the input then this is the best approach in my opinion.
It's not ideal, but as you're stuck with a 3rd party component you can only choose from the methods that are available to you. In this case, your only real options are to find the element based on its class, or its position in the hierarchy. Both might change if the package is updated, but if I had to choose which would be more stable, I'd go for className.

Sublime Text 3 - CSS Autocomplete WITHOUT typing property value

So I know autocomplete works great when you start typing a value. For example, the second you type the "c" in text-align:center, the available autocomplete values pop up (such as center, left, right).
However, when I used Dreamweaver, for properties with specific value options like text-align (center, right, left), display (block, inline-block), cursor (pointer, default), etc., the autocomplete popup would show immediately after the property was typed, it did NOT wait until I started typing a value. Right after text-align: was typed out, it would show me the autocomplete popup giving me the options center, right, left.
The value autocomplete should fire right after my property autocomplete fires:
So after I type te...
the autocomplete popup for "te" properties displays text-align, text-decoration, text-shadow etc....
then I press Enter to select text-align...
then immediately after pressing Enter an autocomplete popup should show for the text-align values: center, left, right.
Any idea how this can be accomplished in Sublime Text 3?
You can get ST to show the autocompletion popup again straight after a completion has been inserted using a small plugin and some preferences:
With a CSS file open in ST, open the Preferences menu and select Preferences - Syntax Specific. Add the following to the settings on the right hand side:
"auto_complete_triggers":
[
{
"characters": ": ",
"selector": "source.css meta.property-list.css meta.property-value.css"
},
],
and save it. This will tell ST to show the autocomplete popup automatically in CSS files when typing a : or a space when the syntax expects a property value.
Now, unfortunately, ST doesn't consider an autocompletion to have "typed" anything, so this trigger isn't fired automatically when selecting a property value like text-align from the autocomplete popup, which inserts text-align:. So, to get round that, this is where we need a small plugin. From the Tools menu, choose Developer -> New Plugin...
Select all text and replace with the following and save it, in the folder ST recommends (Packages/User/) as something like show_autocomplete_after_completion.py:
import sublime
import sublime_plugin
class AutoCompleteListener(sublime_plugin.EventListener):
def on_post_text_command(self, view, command_name, args):
if command_name in ('commit_completion', 'insert_best_completion'):
act = view.settings().get('auto_complete_triggers', [])
scope = view.scope_name(view.sel()[0].begin())
char = view.substr(view.sel()[0].begin() - 1)
for trigger in act:
if sublime.score_selector(scope, trigger['selector']) > 0:
if char in trigger['characters']:
view.run_command('auto_complete', { 'insert_best_completion': False })
break
This plugin basically detects when a completion has been inserted (although due to a limitation of the ST API, it can't detect when you click on an entry with the mouse - see https://github.com/SublimeTextIssues/Core/issues/1166), and if the text/character immediately before the caret matches one of the autocompletion triggers defined in the settings, then it will show the autocomplete popup again.
You can try out this package. This package indexes your .less and .scss (or .sass) and caches your mixins, variables, class or id names and autocompletes both on html and css. It autocompletes your less and sass mixins with mixin arguments. It also supports emmet completions and gets your css classes on popup window. -
https://github.com/subhaze/CSS-Extended/

Why do these radio buttons not let you switch the checked option once you've selected one?

Link to form
The form can be found at the link above.
Up until this morning the radio buttons and the form had been working as expected, however now users can't change their answer once they've picked from one of the two radio buttons even though they use the same input name. Using $("#volunteer-form input:radio[name='gender']:checked").val() I've found that the value is being correctly set and that the two buttons are still linked by a common name. Also, it appears possible to switch between the two using a bit of jQuery, like so:
$("#volunteer-form input[name=gender][value=male]").prop('checked', true);
Any ideas?
its because of your javascript block here:
$(document).ready(function() {
$('.inline').fancybox({
'maxWidth': 600
});
$('.form').click(function(event){
event.preventDefault();
});
});
when you are clicking on the radio button inside the form your preventDefault is stopping the change of radiobutton state ... or maybe you already knew that.
What is the intended purpose of including the preventDefault where you have it?

Form enter key action with lists and AngularJS

In my AngularJS project I have an account details page where you can change your personal account information. This page allows for multiple phone numbers and e-mailaddresses to be supplied. Using mouse input (or tabbing to buttons and pressing them with space bar) works perfectly, however I'd like to add the convenience of the enter key pressing the 'logical' buttons.
My form looks like (accidentally forgot to translate a few items):
A simplified version of the HTML for the form can be found on PasteBin, I've mainly removed the directives for managing the lists.
All buttons are <button> elements except for the cancel button which an <a> to the previous page, and the submit button is <button type="submit">.
When selecting any text box and pressing enter, the first (non-disabled) <button> element is 'clicked'. Meaning if I would change the last name, hit enter, the first phone number would be removed.
When you're in a new entry of phone numbers or e-mailaddresses (the row with the green + button) it should click that button, and if it's disabled do nothing.
When you're in any other text box on the form it should hit the save button, and also if the save button's disabled, do nothing.
Both buttons will be disabled based on form validation.
There'd be no trouble in changing the type of a button from button to submit if that'd help.
I would preferably have an all HTML solution, using just semantics, but I doubt that's really possible. So the logical alternative would be to use an AngularJS directive.
Please do not provide a jQuery or plain JavaScript solution relying on IDs or something like that. I don't want to hack my way around AngularJS, rather embrace it.
In the meantime I've worked on a directive that allows me to declare what I've called 'submit scopes'.
In essence you have actions (inputs) and targets (buttons), they're bound through a service by a key you can assign in the template. To avoid keys from clashing and from simple annoying work you can create a submit-scope which will cause it's children to prepend a unique key to the value they're accessing.
Within a submit-scope you can still override an action to use a global key instead by setting the attribute global-submit="true".
Example code:
<div submit-scope>
<input type="text" submit-action />
<button type="button" submit-target>Pressing enter in the above field will click this button.</button>
</div>
You can view the entire source code and a slightly larger example on Plnkr.
I just tried to replace
<button>Cancel</button>
with
<input type="button" value="Cancel">
and it seems to work correctly...

HTML Select loses selection when re-rendered in Meteor

I have a couple of HTML elements on a page. Whenever the page context is invalidated and it re-renders the elements are re-rendered with no visual cue of the selected option.
If I check for the selection using $('.select1 option:selected') the selected option is returned. However, it is not rendered as selected. If it's a drop-down, then the first element shows up. If it's a multi-line select, the first (firefox) or last (chrome) element shows up with a greyed out select line on it.
If I then click the selected element a second time, it shows up as selected.
Anyone know how to fix this?
I implemented the solution here: Meteor form state not being saved
Store the selected value in a session variable on click:
Template.packageViewer.events({
'change .tagselect': function(){
Session.set('tag', $('.tagselect :selected').html());}
,
'change .groupselect': function(){
Session.set('group', $('.groupselect :selected').html());}
,
'change .packageselect': function(){
Session.set('package', $('.packageselect :selected').val());}
});
Then set the select selected value in the post-render function:
Template.packageViewer.rendered = function(){
$('.groupselect').val(Session.get('group'));
$('.tagselect').val(Session.get('tag'));
}
Hacky, but works.
Maybe you can use $('.select1').trigger("change"); function.