Post image
Strategy

How does this email work? : webdev


I recently treated myself to a bag on sale at Kate Spade. The shipping confirmation email had a sentence with a tracking link in it. I looked at the email the next day and that sentence and link were gone and in their place it read that my package would be delivered the next day. I inspected the email and saw that it’s just a plain ole <p> tag within a table like any other email. I didn’t get a screenshot of the original message so I just posted one of what it says now. I also wish I had paid attention to the subject line because it says my package arrives tomorrow, too. I wonder if it also changed?

Either way I was curious how they did that? Or is this just a modern browser thing with tracking links now?

Post image



Source link

UI loop
Strategy

NgRx With Redux in Angular


Redux is available as a package on NPM for use with a module bundler or in a Node application:

npm install --save redux

Let’s discuss the basic concepts of Redux.

UI loop

So now we will see the overall concept of redux and see hows it works. Here, we can see that we have a UI and when a user performs an action it will change the state of the data.

You may also like:
Angular Tutorial: State Management With NgRx

What Is the State?

All the application data is collectively known as the store and it is to be represented as a state. Also, we cannot change the state as it is immutable. We can change the state only using Action, which itself is an object which included two things:

Type: Type is nothing but it is an Action Name.

Payload: Alternatively, Payload is something we can refer to as Action Data.

Example of Action:

So How’s it works?

1: When data changes, the existing state is duplicated, then a new object is created with the updates. In Angular this data is treated as an RxJS Observable, allowing us to subscribe to it from anywhere in the app.

2: When an event is emitted, for example, a button click, the action is sent to a reducer function to converts the old state into the new state.

{ type: 'DELETE_ITEM', payload: 123 }

Here, you can see that in action, Delete_Item is our action name and 123 is action data.

How to Configure ngRx?

NgRx: The ngRx is an angular version of the redux pattern. Which is inspired by the group of libraries inspired by flux patterns? What do I mean with the “angular/rxjs” version of redux? The angular part is because ngrx is a library to use within an angular application. The rxjs “part is because of the implementation of ngrx works around an rxjs flow.

NgRX

You can set up ngRx with just two steps described below:

1: create one new app with Angular-CLI and give it any name to it.

2: Install the ngrx/store via npm in your system with the following command.

app.module.ts

ngrx.reducer.ts

Now let us understand this concept with the help of the basic example shown below:

Here, in this file, we need to update the app module file with the post reducer, for that we need to import the post reducer.

app.component.ts

Now, we will create one another file in which we create the reducer.

Here we have switch statements with the possible actions and this whole function is collectively known as a reducer. In this function, the switch statement returns the statement as ‘i am learning’ in different languages depending upon the actions.

  • Now if we want to change the state and we will use the class store then we need to implement interface corresponding to the object necessary to pass to the ngModule.
  • A variable for message$ is set as an Observable on the component by calling this.store.select(‘message’).

Thanks for reading!

Now we can subscribe to the Observable in the HTML and trigger changes with button click events.

Conclusion: I hope this blog is useful for you to get the basic understanding of ngrx with redux after reading this blog and you will start using it in your application.

Further Reading

State Management Using NGXS in Angular

Separating State Into Angular Modules With Ngrx

Angular Tutorial: Redux and mat-selection-list



Source link

microsoft visual studios
Strategy

How To Add AutoComplete Textbox In React Application


Introduction

In this article, we are going to learn how we add the AutoComplete textbox in ReactJS. We use the Material UI Autocomplete component in this demo.

Prerequisites

  • We should have the basic knowledge of React.js and Web API.
  • Visual Studio and Visual Studio Code IDE should be installed on your system.
  • SQL Server Management Studio.
  • Material UI Installed.

You may also like: An Angular Autocomplete From UI to DB

Create a Table in the Database

Open SQL Server Management Studio, create a database named “Autocomplete”, and in this database, create a table. Give that table a name like “Tblcountry”.

Now add some demo data in this table.

Create a New Web API project

Open Visual Studio and create a new project.

microsoft visual studios

Change the name to Autocomplete. 

microsoft visual studios

Choose the template as Web API.

microsoft visual studios

Right-click the Models folder from Solution Explorer and go to Add >> New Item >> data.

microsoft visual studios

Click on the “ADO.NET Entity Data Model” option and click “Add”.

microsoft visual studios

Select EF Designer from the database and click the “Next” button.

microsoft visual studios

Add the connection properties and select database names on the next page and click OK.

microsoft visual studios

Check the “Table” checkbox. The internal options will be selected by default. Now, click the “Finish” button

microsoft visual studios

Now, our data model is successfully created.  

Right-click on the Controller folder and add a new controller. Name it as an “Autocomplete controller” and add the following namespace in the Autocomplete controller.

Now add a method to fetch data from the database.

Complete Autocomplete controller code

Now, let’s enable CORS. Go to Tools, open NuGet Package Manager, search for CORS and install the “Microsoft.Asp.Net.WebApi.Cors” package. Open Webapiconfig.cs and add the following lines.

Create ReactJS Project

 Now let’s first create a React application with the following command.

Open the newly created project in the Visual Studio Code and install Material-UI

Install Material-UI

 Now install Material-UI by using the following command

Now install the Axios library by using the following command. Learn more about Axios.

Now go to the src folder and add new components.

Autocomplete.js 

Now open the Autocomplete.js  component and import the required reference.

The following code in this component.

Now open the app.cs file and add the following code.

Now open app.js file and add the following code.

Now run the project by using ‘npm start’,

Did you find this article helpful? Let us know in the comments!

Further Reading

Create an ASP.NET MVC AutoFill Control, Part 1

Fun With React: A Quick Overview

Everything React: Tutorials for Beginners and Experts Alike



Source link

Post image
Strategy

Centering Nav-Bar with Bootstrap and CSS : webdev


I recently published my website to the internet, and my Brother-In-Law, (who used to work in web development) suggested that I use bootstrap, so I decided that I would go and research bootstrap and then implement it into my website. Everything has been going fine so far, but I have run into a problem with my navigation bar, I want it centered like it is in this picture:

Post image

How I want it to look like

Here’s a pic of how it currently looks:

Post image

How it currently looks like

How would I do this?

Here’s my code:

HTML

<!DOCTYPE html>

<html lang="en">

<head>

	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">

	<link rel="stylesheet" type="text/css" href="CSS/All.css">
	<link href="https://fonts.googleapis.com/css?family=Roboto&display=swap" rel="stylesheet">
	<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
	
	

	<title>Keenon's Projects Homepage</title>

</head>

<body>

	<div class="container">

	  <div class="row">

		<div class="col-lg-12">
		
			<h1 class="text-center">Keenon's Projects</h1>

		</div>

	    
		<nav class="navbar navbar-default">
		
			<div class="container">
				
				<!-- Menu Items -->
				<div id="bar">
					
					<ul class="navbar-nav">
			
						<li id="home" class="nav-item"><a href="#" class="nav-link">Home</a></li>
						<li id="projects" class="nav-item"><a href="Projects.html" class="nav-link">Projects</a></li>
						<li id="certs" class="nav-item"><a href="Certs.html" class="nav-link">Certifications</a></li>

					</ul>

				</div>

			</div>

		</nav>


		<div id="aboutPara">

			<h2>About this site</h2>
	
		<p class="para">
	
			Hello my name is Keenon,<br> I made this website for the sole purpose of displaying all my completed projects that I have made and some that I haven't completed yet.<br> This isn't a very fancy site and it doesn't need to be,<br> I just need a place(other than Github) to display my projects.<br>Enjoy.

		</p>

		</div>

		<div id="contactPara">
	
			<h2>Contact Info</h2>

			<p class="para">Here are some links to websites that I am on:<br> <a href="https://github.com/Keenonthedaywalker?tab=repositories" id="git">Github</a><br> <a href="https://www.instagram.com/keenonthedaywalker/">Instagram</a><br> <a href=""></a></p>

		</div>

	  </div>

	</div>

<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.4.1.slim.min.js" integrity="sha384-J6qa4849blE2+poT4WnyKhv5vZF5SrPo0iEjwBvKU7imGFAV0wwj1yYfoRSJoZ+n" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>

</body>

</html>

and CSS:

body {

	text-align: center;
	background-image: url('mainpageBackground.png');

}

h1 {

	color: rgb(0, 200, 200);
	font-size: 100px;

}

li {

	color: rgb(0, 200, 200);
	list-style-type: none;
	font-size: 30px;
	font-family: monospace;

}

#bar .navbar-nav {

	float: none;
	text-align: center;

}

#bar .navbar-nav > li {
  display: inline;
  float: none;
}
#bar .navbar-nav > li > a {
  display: inline;
}

a:visited {

	color: rgb(200, 200, 200);

}

a:link {

	color: rgb(200, 200, 200);

}

#aboutPara {

	margin-top: 150px;

}

.para {

	color: white;

}

h2 {

	color: rgb(0, 200, 200);

	font-size: 40px;

	margin-top: 30px;

	text-decoration: underline;

}

#git {

	padding-top: 40px;

}

#projectsPara {

	margin-top: 100px;

}

#vbwc {

	width: 70%;
	height: 100%;
	margin-top: 50px;

}

#die {

	width: 50%;
	height: 50%;

}

#vpp {

	width: 50%;
	height: 50%;

}

p {

	font-size: 20px;
	font-family: roboto, monospace;
}

h3 {

	color: rgb(0, 200, 200);

	font-size: 35px;

	margin-top: 30px;

	text-decoration: underline;

}

.certLinks {

	display: list-item;

}





Source link

Building an accessible autocomplete control by Adam Silver
Strategy

Building an accessible autocomplete control by Adam Silver


This is an excerpt from my book, Form Design Patterns.

This article starts in the middle of chapter 3, A Flight Booking Form where I’ve been looking at ways to let users enter a destination country.

Unfortunately, native HTML form controls just aren’t good enough for this type of interaction.

And so we need to build a custom autocomplete control from scratch.

A word of warning though: this is one of the hardest UI components I’ve ever had to make—they’re just way harder than they look.

An autocomplete control showing 3 suggestions with the second option highlighted.

An autocomplete control shows suggestions that match what the user types as they type.

Users can select a suggestion to complete their entry quickly and accurately or keep typing to further refine the suggested options.

The basic markup

To make it work when JavaScript is unavailable we need to start with a native form control that browsers provide for free.

As explained earlier, there are too many options for radio buttons; a search box is slow to use and can lead to zero results; and datalist is too buggy – which leaves us with the select box.

<div class="field">
  <label for="destination">
    <span class="field-label">Destination</span>
  </label>
  <select name="destination" id="destination">
    <option value="">Select</option>
    <option value="1">France</option>
    <option value="2">Germany</option>
    <!-- … -->
  </select>
</div>

The enhanced markup

When JavaScript is available, our yet-to-be-written Autocomplete() constructor will enhance the basic HTML into this:

<div class="field">
  <label for="destination">
    <span class="field-label">Destination</span>
  </label>
  <select name="destination" aria-hidden="true" tabindex="-1" class="visually-hidden">
    <!-- options here -->
  </select>
  <div class="autocomplete">
    <input aria-owns="autocomplete-options--destination" autocapitalize="none" type="text" autocomplete="off"  aria-autocomplete="list" role="combobox" id="destination" aria-expanded="false">
    <svg focusable="false" version="1.1" xmlns="http://www.w3.org/2000/svg">
      <!-- rest of SVG here -->
    </svg>
    <ul id="autocomplete-options--destination" role="listbox" class="hidden">
      <li role="option" tabindex="-1" aria-selected="false" data-option-value="1" id="autocomplete_1">
    	  France
      </li>
      <li role="option" tabindex="-1" aria-selected="true" data-option-value="2" id="autocomplete_2">
    	  Germany
      </li>
      <!-- more options here -->
    </ul>
    <div aria-live="polite" role="status" class="visually-hidden">
  	13 results available.
    </div>
  </div>
</div>

Hiding the select box without stopping its value being submitted

To hide the select box without stopping its value from being submitted to the server involves adding:

  • visually-hidden to hide it from sighted users
  • aria-hidden="true" to hide it from screen reader users
  • tabindex="-1" to stop keyboard users from being able to focus it

If you’re using all 3 attributes, it’s normally better to use display: none because it achieves the same affect with cleaner code.

But this would stop the select box’s value from being submitted to the server. This is important because while the user won’t be interacting with the select box directly, its value is still submitted for processing.

Reassociating the label

The select box’s id attribute is transferred over to the text box because the label must be associated to it so it’s read out in screen readers, and to increase the hit area of the control as explained in chapter 1, “A Registration Form”.

The text box’s name attribute isn’t needed because its value isn’t sent to the server – it’s purely for interaction purposes and is used as a proxy to set the select box value behind the scenes.

Text box attribute notes

The role="combobox" attribute will ensure the input is announced as a combo box. A combo box is “an edit control with an associated list box that provides a set of predefined choices.”

The aria-autocomplete="list" attribute tells users that a list of options will appear. The aria-expanded attribute tells users whether the menu is expanded or collapsed by toggling its value between true and false.

The autocomplete="off" attribute stops browsers from showing their own suggestions, which would interfere with those offered by our component.

Finally, the autocapitalize="none" attribute stops browsers from automatically capitalizing the first letter. More on this in chapter 4, A Login Form.

The SVG icon is overlaid on the text box using CSS. The focusable="false" attribute fixes the issue that in Internet Explorer SVG elements are focusable by default.

The role="list" attribute is used to communicate the menu as a list, because it will be populated with a list of options. Each option has a role="option" attribute.

The aria-selected="true" attribute tells users which option within the list is selected or not by toggling the value between true and false.

The tabindex="-1" attribute means focus can be set to the option programmatically when users press certain keys. We’ll look at keyboard interaction later.

The data-option-value attribute stores the select box option value. When the user clicks an autocomplete option, the select box value is updated to keep them in sync. This ties the interface (what the user sees) with the select box value (what the user can’t see) that’s sent to the server.

Using a live region to make sure screen reader users know when options are suggested

Sighted users will see the suggestions appear in the menu as they type, but the act of populating the menu isn’t determinable to screen reader users without leaving the text box to explore the menu.

To provide a comparable experience (inclusive design principle 1), we’ll use a live region as explained in “A Checkout Form.”

As the menu is generated, the live region will be populated with how many results are available; for example, “13 results available.” With this information to hand, users can decide to keep typing to narrow the results or to select a suggestion from the menu.

As the feedback is only useful to screen reader users, it’s hidden using visually-hidden again.

Handling text input from the user

When the user types into the text box, we need to listen for certain keystrokes using JavaScript.

Autocomplete.prototype.createTextBox = function() {
  this.textBox.on('keyup', $.proxy(this, 'onTextBoxKeyUp'));
};

Autocomplete.prototype.onTextBoxKeyUp = function(e) {
  switch (e.keyCode) {
    case this.keys.esc:
    case this.keys.up:
    case this.keys.left:
    case this.keys.right:
    case this.keys.space:
    case this.keys.enter:
    case this.keys.tab:
    case this.keys.shift:
      // ignore otherwise the menu will show
      break;
    case this.keys.down:
      this.onTextBoxDownPressed(e);
      break;
    default:
      this.onTextBoxType(e);
  }
};

The this.keys object is a collection of numbers that correspond to particular keys by their names. This is to avoid magic numbers, which makes the code easier to understand.

The switch statement filters out Escape, Up, Left, Right, Space, Enter, Tab, and Shift keys. If it didn’t, the default case would run and incorrectly show the menu.

Instead of filtering out the keys we aren’t concerned with, we could’ve specified the keys that we are concerned with. But this would mean specifying a huge range of keys, which would increase the chance of one being missed.

We’re mainly interested in the last two statements: when the user presses Down and the default case above which means everything else (a character, number, symbol, and so on). In this case the onTextBoxType() function will be called.

Autocomplete.prototype.onTextBoxType = function(e) {
  // only show options if user typed something
  if(this.textBox.val().trim().length > 0) {
    // get options based on value
    var options = this.getOptions(this.textBox.val().trim().toLowerCase());

    // build the menu based on the options
    this.buildMenu(options);

    // show the menu
    this.showMenu();

    // update the live region
    this.updateStatus(options.length);
  }

  // update the select box value which
  // the server uses to process the data
  this.updateSelectBox();
};

The getOptions() method (covered later) filters the options based on what the user typed.

Composite controls should have a single tab stop

The autocomplete control is a composite control which means it has different interactive and focusable parts. For example, users type in the text box and they move to the menu to select a suggestion.

Composite components should only have one tab stop like the WAI-ARIA Authoring Practices 1.1 specification says:

A primary keyboard navigation convention common across all platforms is that the tab and shift+tab keys move focus from one UI component to another while other keys, primarily the arrow keys, move focus inside of components that include multiple focusable elements. The path that the focus follows when pressing the tab key is known as the tab sequence or tab ring.

A set of radio buttons is a composite control too.

Once the first radio button is focused, users can use the arrow keys to move between each option. Pressing Tab will move focus to the next focusable control in the tab sequence.

Back to the autocomplete.

The text box is naturally focusable by the Tab key. Once focused, the user will be able to press the arrow keys to traverse the menu, which we’ll look at shortly.

Pressing Tab when the text box or menu option is focused should hide the menu to stop it from obscuring the content beneath when not in use. We’ll look at how to do this shortly.

ARIA activedescendant doesn’t work for an autocomplete control

A lot of autocompletes use the aria-activedescendant attribute as an alternative way to make sure there’s just one tab stop.

It works by keeping focus on the component’s container at all times and referencing the currently active element.

But this doesn’t work for an autocomplete control because the text box is a sibling—not a parent—of the menu.

The onblur event is triggered when the user leaves an in-focus element. In the case of the autocomplete, we could listen to this event on the text box.

The virtue of using the onblur event is that it will be triggered when the user leaves the field by pressing Tab and by clicking or tapping outside the element.

this.textBox.on('blur', function(e) { // hide menu });

Unfortunately, the act of moving focus programmatically to the menu triggers the blur event, which will hide the menu. This makes the menu inaccessible to keyboard users.

One solution involves using setTimeout(), which lets us put a delay on the event. The delay gives us time to cancel the event using clearTimeout() should the user move focus to the menu within that time.

This stops the menu being hidden making it accessible again.

this.textBox.on('blur', $.proxy(function(e) {
  // set a delay before hiding the menu
  this.timeout = window.setTimeout(function() {
    // hide menu
  }, 100);
}, this));

this.menu.on('focus', $.proxy(function(e) {
  // cancel the hiding of the menu
  window.clearTimeout(this.timeout);
}, this));

But this doesn’t work because there’s a problem with the blur event in iOS 10. It incorrectly triggers the blur event on the text box when the user hides the on-screen keyboard. This stops users from accessing the menu altogether.

The actual solution is next.

Instead of hiding the menu using the blur event, we can use the keydown event to listen out for when the user presses the Tab key.

this.textBox.on('keydown', $.proxy(function(e) {
  switch (e.keyCode) {
    case this.keys.tab:
      // hide menu
      break;
  }
}, this));

But unlike the blur event, this solution doesn’t cover the case where users blur the control by clicking outside of it.

So we’ll cover that by listening to the document’s click event and making sure we only hide the menu if the user clicks outside of the control.

$(document).on('click', $.proxy(function(e) {
  if(!this.container[0].contains(e.target)) {
    // hide the menu
  }
}, this));

When the text box is focused, pressing Down triggers onTextBoxDownPressed().

Autocomplete.prototype.onTextBoxDownPressed = function(e) {
  var option;
  var options;
  var value = this.textBox.val().trim();
  /*
    When the value is empty or if it exactly
    matches an option show the entire menu
  */
  if(value.length === 0 || this.isExactMatch(value)) {

    // get options based on the value
    options = this.getAllOptions();

    // build the menu based on the options
    this.buildMenu(options);

    // show the menu
    this.showMenu();

    // retrieve the first option in the menu
    option = this.getFirstOption();

    // highlight the first option
    this.highlightOption(option);

  /*
    When there’s a value that doesn’t have
    an exact match show the matching options
  */
  } else {

    // get options based on the value
    options = this.getOptions(value);

    // if there are options
    if(options.length > 0) {

      // build the menu based on the options
      this.buildMenu(options);

      // show the menu
      this.showMenu();

      // retrieve the first option in the menu
      option = this.getFirstOption();

      // highlight the first option
      this.highlightOption(option);
    }
  }
};

If the user presses Down without having typed anything, the menu will show all options and then focus the first one.

The same thing will happen if the user types an exact match. This will be rare because most users who spot the suggestions will select one as it’s quicker.

The else condition will populate options that match (if any), and then focus the first one. At the end of both scenarios highlightOption() is called, which we’ll look at shortly.

The menu may contain hundreds of options. To ensure the menu items are visible, we’ll use the following styles.

.autocomplete [role=listbox] {
  max-height: 12em;
  overflow-y: scroll;
  -webkit-overflow-scrolling: touch;
}

The max-height property lets the menu grow to a maximum height. Once the content inside the menu surpasses that height, users can scroll the menu thanks to the overflow-y: scroll property.

The last, non-standard property enables momentum scrolling on iOS. This ensures the autocomplete control scrolls the same way as it would everywhere else.

Selecting an option

We’ll use event delegation to listen to when the user clicks an option which is more efficient than adding a click event to each option.

Autocomplete.prototype.createMenu = function() {
  this.menu.on('click', '[role=option]', $.proxy(this, 'onOptionClick'));
};

Autocomplete.prototype.onOptionClick = function(e) {
  var option = $(e.currentTarget);
  this.selectOption(option);
};

The event handler retrieves the option (e.currentTarget) and hands it off to selectOption().

Autocomplete.prototype.selectOption = function(option) {
  var value = option.attr('data-option-value');
  this.setValue(value);
  this.hideMenu();
  this.focusTextBox();
};

The selectOption() method takes the option to be selected and extracts the value of the data-option-value attribute. It’s then passed to setValue() which populates the text box and hidden select box. Finally, the menu is hidden and the textbox is focused.

This same routine is performed when the user selects an option with the Space or Enter keys.

Once focus is within the menu, we can let users traverse the menu with the keyboard by listening to the keydown event.

Autocomplete.prototype.createMenu = function() {
  this.menu.on('keydown', $.proxy(this, 'onMenuKeyDown'));
};

Autocomplete.prototype.onMenuKeyDown = function(e) {
  switch (e.keyCode) {
    case this.keys.up:
      // Do stuff
      break;
    case this.keys.down:
      // Do stuff
      break;
    case this.keys.enter:
      // Do stuff
      break;
    case this.keys.space:
      // Do stuff
      break;
    case this.keys.esc:
      // Do stuff
      break;
    case this.keys.tab:
      // Do stuff
      break;
    default:
      this.textBox.focus();
  }
};
Key Action
Up If the first option is focused, set focus to the text box. Otherwise set focus to the previous option.
Down Focus the next menu option. If it’s the last menu option, do nothing.
Tab Hide the menu.
Enter or Space Select the currently highlighted option and focus the text box.
Escape Hide the menu and focus the text box.
Everything else Focus the text box (so users can continue typing).

Highlighting the focused options

When the user focuses an option by pressing the Up or Down keys, highlightOption() is called.

Autocomplete.prototype.highlightOption = function(option) {
  // if there’s a currently selected option
  if(this.activeOptionId) {

    // get the option
    var activeOption = this.getOptionById(this.activeOptionId);

    // unselect the option
    activeOption.attr('aria-selected', 'false');
  }

  // set new option to selected
  option.attr('aria-selected', 'true');

  // If the option isn’t visible within the menu
  if(!this.isElementVisible(option.parent(), option)) {

    // make it visible by setting its position inside the menu
    option.parent().scrollTop(option.parent().scrollTop() + option.position().top);
  }

  // store new option for next time
  this.activeOptionId = option[0].id;

  // focus the option
  option.focus();
};

The method performs several tasks.

First, it checks to see if there’s a previously active option. If so, the aria-selected attribute is set to false, which ensures the state is communicated to screen reader users.

Second, the new option’s aria-selected attribute is set to true.

As the menu has a fixed height, the newly focused option could be out of the menu’s visible area. So we check whether this is the case using isElementVisible().

If it’s not visible, the menu’s scroll position is adjusted using scrollTop(), which makes sure it’s in view.

Next, the new option is stored so that it can be referenced later when the method is called again for a different option. And finally, the option is focused to ensure its value is announced in screen readers.

To provide feedback to sighted users we can use the same [aria-selected=true] CSS attribute selector like this:

.autocomplete [role=option][aria-selected="true"] {
  background-color: #005EA5;
  border-color: #005EA5;
  color: #ffffff;
}

Tying state and style together is good because it ensures that state changes are communicated interoperably. Form should follow function, and doing so directly keeps them in-sync.

Filtering the options

A good filter forgives small typos and mixed letter casing.

A quick recap: remember that the data driving the suggestions reside in the <option>s.

<select>
  <option value="">Select</option>
  <option value="1">France</option>
  <option value="2">Germany</option>
</select>

As noted above, getOptions() is called when we need to populate the menu with matching options.

Autocomplete.prototype.getOptions = function(value) {
  var matches = [];

  // Loop through each of the option elements
  this.select.find('option').each(function(i, el) {
    el = $(el);
    // if the option has a value and the option’s text node matches the user-typed value
    if(el.val().trim().length > 0 && el.text().toLowerCase().indexOf(value.toLowerCase()) > -1) {

      // push an object representation to the matches array
      matches.push({ text: el.text(), value: el.val() });
    }
  });

  return matches;
};

The method takes the user-entered value as a parameter. It then loops through each of the <option>s and compares the value to the option’s text content (the bit inside the element).

It does so by using indexOf() which checks to see if it contains an occurence of the specified value. This means users can type incomplete parts of countries and still have relevant suggestions shown to them.

The value is trimmed and converted to lowercase, which means options will still be shown if the user has, for example, turned on caps lock. Users shouldn’t have to fix problems we can fix for them automatically.

Each matched option is added to the matches array, which will be used by the calling function to populate the menu.

Supporting endonyms and typos

An endonym is a name used by the people from a particular area of that area (or themselves or their language).

For example, Germany in German is “Deutschland.” We can follow inclusive design principle 5, “Offer choice,” by letting users type an endonym.

To do this, we first need to store it somewhere. We can put the endonym inside a data attribute on the <option> element.

<select>
  <!-- more options -->
  <option value="2" data-alt="Deutschland">Germany</option>
  <!-- more options -->
</select>

Now we can change the filter function to check the alternative value like this:

Autocomplete.prototype.getOptions = function(value) {
  var matches = [];

  // Loop through each of the option elements
  this.select.find('option').each(function(i, el) {
    el = $(el);

    // if the option has a value and the option’s text node matches the user-typed value or the option’s data-alt attribute matches the user-typed value
    if( el.val().trim().length > 0
  	&& el.text().toLowerCase().indexOf(value.toLowerCase()) > -1
  	|| el.attr('data-alt')
  	&& el.attr('data-alt').toLowerCase().indexOf(value.toLowerCase()) > -1 ) {

      // push an object representation to the matches array
      matches.push({ text: el.text(), value: el.val() });
    }
  });

  return matches;
};

You can use the same attribute to store common typos if you like.

Demo

And that’s it. Here’s a demo.



Source link

Post image
Strategy

Yoast meta description being overwritten by….Avada? Someth…


Hello everyone,

I built my site using Avada Fusionbuilder in WordPress, and am using the Yoast SEO plugin. I’ve entered various search snippets/meta descriptions into Yoast.

However, Google still shows a specific meta description, which I believe is the result of there being two meta descriptions in the source code – Yoast’s one, and another right at the top. As you can see in the code below: the red block is the meta snippet google shows, and I have no idea why it’s there. The black block(s) are meta snippets I entered myself into Yoast.

The only option I found in Avada settings was something called “Open Graph Meta Tags” which I turned off, but it still hasn’t resolved.

Does anyone know why this is happening? I’m not running any other SEO plugins.

Post image



Source link