HTML View doesn't display updated model - html

I have an HTML file which displays 2 lists using AngularJS file with 2 controllers and a service. The lists are arrays which are being correctly updated in the model, as evidenced by the console.log output. But the HTML doesn't display the updated list2 (data stored in the angularJS service). Can someone tell where I am going wrong?
Tried looking at the API, angular directives, Controller As syntax and inheritance concepts.
index.html
<!DOCTYPE html>
<html lang="en" ng-app="ShoppingListCheckOff">
<head>
<title>Shopping List Check Off</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="styles/bootstrap.min.css" />
<script src="angular.min.js"></script>
<script src="app.js"></script>
<style>
.emptyMessage {
font-weight: bold;
color: red;
font-size: 1.2em;
}
li {
margin-bottom: 7px;
font-size: 1.2em;
}
li > button {
margin-left: 6px;
}
button > span {
color: green;
}
</style>
</head>
<body>
<div class="container">
<h1>Shopping List Check Off</h1>
<div class="row">
<!-- To Buy List -->
<div class="col-md-6" ng-controller="ToBuyController as toBuy">
<h2>To Buy:</h2>
<ul>
<li ng-repeat="item in toBuy.list">
Buy {{ item.name }} {{ item.quantity }}
<button ng-click="toBuy.bought($index)" class="btn btn-default">
<span class="glyphicon glyphicon-ok"></span> Bought
</button>
</li>
</ul>
<div ng-if="!toBuy.list.length" class="emptyMessage">Everything is bought!</div>
</div>
<!-- Already Bought List -->
<div class="col-md-6">
<h2>Already Bought:</h2>
<ul>
<li ng-repeat="item in bought.list">Bought {{ item.quantity }} {{ item.name }}</li>
</ul>
<div ng-if="!bought.list.length" class="emptyMessage">Nothing bought yet.</div>
</div>
</div>
</div>
</body>
</html>
App.js
(function() {
'use strict';
angular
.module('ShoppingListCheckOff', [])
.controller('ToBuyController', ToBuyController)
.controller('AlreadyBoughtController', AlreadyBoughtController)
.service('ShoppingListCheckOffService', ShoppingListCheckOffService);
ToBuyController.$inject = ['ShoppingListCheckOffService'];
function ToBuyController(ShoppingListCheckOffService) {
var toBuy = this;
toBuy.list = ShoppingListCheckOffService.getList(1);
toBuy.bought = function(itemIndex) {
ShoppingListCheckOffService.transfer(itemIndex);
};
}
AlreadyBoughtController.$inject = ['ShoppingListCheckOffService'];
function AlreadyBoughtController(ShoppingListCheckOffService) {
var bought = this;
bought.list = ShoppingListCheckOffService.getList(2);
}
function ShoppingListCheckOffService() {
var service = this;
// List of shopping items
var list1 = [
{ name: 'Cookies', quantity: 10 },
{ name: 'Bananas', quantity: 100 },
{ name: 'Toys', quantity: 6 },
{ name: 'Dildos', quantity: 300 },
{ name: 'Yaakovs', quantity: 1 }
];
var list2 = [];
service.transfer = function(itemIndex) {
list2 = list2.concat(list1.splice(itemIndex, 1));
console.log('List 1', list1);
console.log('List 2', list2);
};
service.getList = function(num) {
if (num == 1) {
return list1;
}
if (num == 2) {
return list2;
}
};
}
})();

The issue is that concat does not change the original array. It creates a new array. When you do list2 = list2.concat(list1.splice(itemIndex, 1)); you are setting list2 to a new array but bought.list is still set to the old array so it doesn't change.
One solution would be to
replace
list2 = list2.concat(list1.splice(itemIndex, 1));
with
list2.push(list1.splice(itemIndex, 1)[0]);

Related

add class to two different button in x-editable angular

here I want to add two different class to two button using x-editable angular.
<div ng-app="app" ng-controller="Ctrl">
<div>Email: {{ user.email || 'empty' }}</div>
</div>
you need to configure for all the buttons at once like so
app.run(function(editableOptions, editableThemes) {
editableOptions.theme = 'bs3';
editableThemes.bs3.buttonsClass = 'class1';
});
var app = angular.module("app", ["xeditable"]);
app.run(function(editableOptions, editableThemes) {
editableOptions.theme = 'bs3';
editableThemes.bs3.buttonsClass = 'class1';
});
app.controller('Ctrl', function($scope) {
$scope.user = {
name: 'awesome user'
};
});
div[ng-app] {
margin: 50px;
}
.class1 {
color: green !important;
}
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<link href="http://vitalets.github.io/angular-xeditable/dist/css/xeditable.css" rel="stylesheet" />
<script src="http://vitalets.github.io/angular-xeditable/dist/js/xeditable.js"></script>
<h4>Angular-xeditable Customize input (Bootstrap 3)</h4>
<div ng-app="app" ng-controller="Ctrl">
<a href="#" editable-text="user.name" e-required e-placeholder="Enter name" e-class="class1 class2">
{{ (user.name || 'empty') | uppercase }}
</a>
</div>

want to directly add class to input element when click on editable fields in x-editable angular

here I am using Angular x-editable. I want to add the class directly to the input element and buttons
<div ng-app="app" ng-controller="Ctrl">
<div>Email: {{ user.email || 'empty' }}</div>
</div>
How about using e-class="class1 class2" refer here
var app = angular.module("app", ["xeditable"]);
app.run(function(editableOptions) {
editableOptions.theme = 'bs3';
});
app.controller('Ctrl', function($scope) {
$scope.user = {
name: 'awesome user'
};
});
div[ng-app] {
margin: 50px;
}
.class1 {
color: green !important;
}
<link href="https://netdna.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.4/angular.min.js"></script>
<link href="http://vitalets.github.io/angular-xeditable/dist/css/xeditable.css" rel="stylesheet"/>
<script src="http://vitalets.github.io/angular-xeditable/dist/js/xeditable.js"></script>
<h4>Angular-xeditable Customize input (Bootstrap 3)</h4>
<div ng-app="app" ng-controller="Ctrl">
<a href="#" editable-text="user.name" e-required e-placeholder="Enter name" e-class="class1 class2">
{{ (user.name || 'empty') | uppercase }}
</a>
</div>

Material design for web - how to make an autocomplete input

I am using google's material design for web. And I would like to use their select component as an autocomplete component. What I am aiming for is the autocomplete you can see in react mui. I have removed the disabled and readonly input attributes but I still can't write anything to input field.
<div class="mdc-select demo-width-class">
<div class="mdc-select__anchor">
<span class="mdc-select__ripple"></span>
<input type="text" class="mdc-select__selected-text">
<i class="mdc-select__dropdown-icon"></i>
<span class="mdc-floating-label">Pick a Food Group</span>
<span class="mdc-line-ripple"></span>
</div>
<div class="mdc-select__menu mdc-menu mdc-menu-surface mdc-menu-surface--fullwidth">
<ul class="mdc-list">
<li class="mdc-list-item mdc-list-item--selected" data-value="" aria-selected="true"></li>
<li class="mdc-list-item" data-value="grains">
<span class="mdc-list-item__text">
Bread, Cereal, Rice, and Pasta
</span>
</li>
<li class="mdc-list-item" data-value="vegetables">
<span class="mdc-list-item__text">
Vegetables
</span>
</li>
<li class="mdc-list-item" data-value="fruit">
<span class="mdc-list-item__text">
Fruit
</span>
</li>
</ul>
</div>
</div>
How can I enable the input field for writing into it, so that I can adapt and make an autocomplete input field?
since you have mentioned that you would like to see an answer without using react, thus in plain javascript. I have managed to do just that. I have combined the css and markup from #Sifat Haque's answer and the full working autocomplete logic from w3schools. Though this may seem simple, it was quite a hassle to make this work.
const select = new mdc.select.MDCSelect(document.querySelector('.mdc-select'));
function autocomplete(inp, arr) {
var currentFocus;
inp.addEventListener("input", autocomp);
inp.addEventListener("click", autocomp);
inp.addEventListener("focus", autocomp);
function autocomp(e) {
var a, b, i, val = this.value;
closeAllLists();
currentFocus = -1;
a = document.createElement("ul");
a.setAttribute("id", this.id + "autocomplete-list");
a.setAttribute("class", "autocomplete-items mdc-list");
document.getElementById("autocomp").appendChild(a);
for (i = 0; i < arr.length; i++) {
if (arr[i].substr(0, val.length).toUpperCase() == val.toUpperCase() || (val.trim()).length == 0) {
b = document.createElement("li");
b.setAttribute("class", "mdc-list-item")
b.innerHTML = "<span class='mdc-list-item__text'>" + arr[i] + "</span>";
b.innerHTML += "<input type='hidden' value='" + arr[i] + "'>";
b.addEventListener("click", function(e) {
inp.value = this.getElementsByTagName("input")[0].value;
closeAllLists();
});
a.appendChild(b);
}
}
}
inp.addEventListener("keydown", function(e) {
var x = document.getElementById(this.id + "autocomplete-list");
if (x) x = x.getElementsByTagName("li");
if (e.keyCode == 40) {
currentFocus++;
addActive(x);
} else if (e.keyCode == 38) { //up
currentFocus--;
addActive(x);
} else if (e.keyCode == 13) {
e.preventDefault();
if (currentFocus > -1) {
if (x) x[currentFocus].click();
}
}
});
function addActive(x) {
if (!x) return false;
removeActive(x);
if (currentFocus >= x.length) currentFocus = 0;
if (currentFocus < 0) currentFocus = (x.length - 1);
x[currentFocus].classList.add("autocomplete-active");
x[currentFocus].classList.add("mdc-list-item--selected");
}
function removeActive(x) {
for (var i = 0; i < x.length; i++) {
x[i].classList.remove("autocomplete-active");
x[i].classList.remove("mdc-list-item--selected");
}
}
function closeAllLists(elmnt) {
var x = document.getElementsByClassName("autocomplete-items");
for (var i = 0; i < x.length; i++) {
if (elmnt != x[i] && elmnt != inp) {
x[i].parentNode.removeChild(x[i]);
}
}
}
}
/*An array containing all the foods :*/
var foods = ["fruit", "vegetables", "grains", "fries"];
/*initiate the autocomplete function on the "myInput" element, and pass along the foods array as possible autocomplete values:*/
autocomplete(document.getElementById("name-input"), foods);
function makeActive(element) {
document.getElementById("name-input").focus();
element.classList.add("mdc-select--focused");
element.classList.add("mdc-select--activated")
}
* {
box-sizing: border-box;
}
.autocomplete {
position: relative;
display: inline-block;
}
input {
border: 1px solid transparent;
background-color: #f1f1f1;
padding: 10px;
font-size: 16px;
}
input[type=text] {
background-color: transparent;
width: 100%;
margin-left: -200px;
margin-top: 30px;
z-index: -2;
}
input[type=text]:active {
border: none;
}
.autocomplete-items {
position: absolute;
border: 1px solid #d4d4d4;
border-bottom: none;
border-top: none;
z-index: 99;
/*position the autocomplete items to be the same width as the container:*/
top: 100%;
left: 0;
right: 0;
max-height: 200px;
/*overflow-y: scroll; */
}
.autocomplete-items li {
padding: 10px;
cursor: pointer;
background-color: #fff;
border-bottom: 1px solid #d4d4d4;
}
.mdc-select__menu {
margin-top: -30px;
z-index: 1;
height: 150px;
box-shadow: none;
background-color: transparent;
overflow-x: hidden !important;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<link href="https://unpkg.com/material-components-web#v4.0.0/dist/material-components-web.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script src="https://unpkg.com/material-components-web#v4.0.0/dist/material-components-web.min.js"></script>
</head>
<body>
<h2>Autocomplete</h2>
<p>Start typing:</p>
<!--Make sure the form has the autocomplete function switched off:-->
<form autocomplete="off" action="" method="post">
<div class="mdc-select" onclick="makeActive(this)">
<div class="mdc-select__anchor demo-width-class">
<i class="mdc-select__dropdown-icon"></i>
<div class="mdc-select__selected-text"></div>
<span class="mdc-floating-label">Pick a Food Group</span>
<div class="mdc-line-ripple"></div>
<input type="text" id="name-input" name="selectione">
</div>
<div class="mdc-select__menu mdc-menu mdc-menu-surface">
<div class="autocomplete" id='autocomp' style="width:200px;">
</div>
</div>
</div>
<input type="submit">
</form>
Hope this helps!
edit: added standard selection option
I've created a demo and it somewhat does what you want. The two issues it has are-
User has to click twice(double click) to input values(I can't to make it work on a single click)
The position of the label overlaps the selected value(Even after giving another class or styling it dynamically)
If anybody has any idea about how to go through these issues, their ideas are
welcome. #Leff, you yourself look like a person with experience, can
you solve them? If yes, please do so and please also enlighten us(me).
Also, I've used jquery in this code if you're looking for only vanilla javascript, you might have to do it yourself or find a person who can as I'm no expert in that area but that's the logical part. Your main problem seemed to be of HTML which should be resolved.
Below is the demo, see if it helps you.
// initialize
const select = new mdc.select.MDCSelect(document.querySelector('.mdc-select'));
// stop the original propagation so that input field remains editable
$('#food').on('click', (event) => {
return false;
});
// Demo Data
const foodArr = ['Bread, Cereal, Rice, and Pasta', 'Vegetables', 'Fruit'];
// You'll have to use ajax here to get the data
$('#food').on('keyup', (event) => {
//console.clear();
let $this = $(event.currentTarget);
let currValue = $this.val();
let search = new RegExp(currValue, 'i'); // prepare a regex object // Your custom condition
let matchArr = foodArr.filter(item => search.test(item)); //store the result in an array
let $select = "";
// check if array is empty
if (matchArr.length > 0) {
// map the elements of the array and create option html
matchArr.forEach((item) => {
$select += `<li class="mdc-list-item" data-value="${item}"> ${item}</li>`;
})
} else { // if array is empty, display no match
$select += `<li class="mdc-list-item" id="no_match"> No match found!</li>`;
}
//console.log(matchArr);
// if the data was selected before, unselect it
$('.mdc-list-item--selected:first').attr({'data-value': ''});
$('.mdc-list-item--selected:first').text('');
$('.mdc-list-item--selected:not(:first)').removeClass('mdc-list-item--selected');
// remove all previous option elements
$('.mdc-list-item:not(.mdc-list-item--selected:first)').remove();
// add new option elements
$('.mdc-list-item--selected').after($select);
// start the click function, so that dropdown doesn't close
$this.click();
});
// When any option is selected, show it on input field
$(document).on('click', '.mdc-list-item:not(#no_match)', (event) => {
let $this = $(event.currentTarget);
$this.addClass('mdc-list-item--selected');
$('.mdc-floating-label').addClass('mdc-floating-label--float-above');
$('.mdc-select__anchor').addClass('demo-width-class mdc-ripple-upgraded')
$('.mdc-line-ripple').addClass('mdc-line-ripple--active mdc-line-ripple--deactivating')
$('.mdc-line-ripple').css({'transform-origin': '182px center'})
$('#food').val($this.attr('data-value'));
// return false;
// event.stopImmediatePropagation()
});
// if clicked on no match, value of input field should be empty, alternatively you can also make option disabled
$(document).on('click', '#no_match', (event) => {
$('#food').val('');
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>#sauhardnc</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link href="https://unpkg.com/material-components-web#v4.0.0/dist/material-components-web.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script src="https://unpkg.com/material-components-web#v4.0.0/dist/material-components-web.min.js"></script>
</head>
<body>
<div class="mdc-select">
<div class="mdc-select__anchor demo-width-class" style="width: 100%">
<i class="mdc-select__dropdown-icon"></i>
<input type="text" class="mdc-select__selected-text" id="food"></input>
<!-- Give a unique id -->
<!--<div contenteditable="true" class="mdc-select__selected-text" id="fruit"></div>-->
<span class="mdc-floating-label">Pick a Food Group</span>
<div class="mdc-line-ripple"></div>
</div>
<div class="mdc-select__menu mdc-menu mdc-menu-surface demo-width-class" style="width: 100%">
<ul class="mdc-list">
<li class="mdc-list-item mdc-list-item--selected" data-value="" aria-selected="true"></li>
<li class="mdc-list-item" data-value="Bread, Cereal, Rice, and Pasta">
Bread, Cereal, Rice, and Pasta
</li>
<li class="mdc-list-item" data-value="Vegetables">
Vegetables
</li>
<li class="mdc-list-item" data-value="Fruit">
Fruit
</li>
</ul>
</div>
</div>
</body>
</html>
You need to combine the input fields along with the select to get an input field and then write some javascript to get the autocomplete functionality. You can check my solution.
console.clear();
const select = new mdc.select.MDCSelect(document.querySelector('.mdc-select'));
select.listen('MDCSelect:change', () => {
alert(`Selected option at index ${select.selectedIndex} with value "${select.value}"`);
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<link href="https://unpkg.com/material-components-web#v4.0.0/dist/material-components-web.min.css" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<script src="https://unpkg.com/material-components-web#v4.0.0/dist/material-components-web.min.js"></script>
</head>
<body>
<div class="mdc-select">
<div class="mdc-select__anchor demo-width-class">
<i class="mdc-select__dropdown-icon"></i>
<div class="mdc-select__selected-text"></div>
<span class="mdc-floating-label">Pick a Food Group</span>
<div class="mdc-line-ripple"></div>
</div>
<div class="mdc-select__menu mdc-menu mdc-menu-surface demo-width-class">
<ul class="mdc-list">
<input type="text" class="mdc-list-item--selected mdc-text-field__input" id="name-input">
<label for="name-input" class="mdc-floating-label">search....</label>
<li class="mdc-list-item" data-value="grains">
Bread, Cereal, Rice, and Pasta
</li>
<li class="mdc-list-item" data-value="vegetables">
Vegetables
</li>
<li class="mdc-list-item" data-value="fruit">
Fruit
</li>
<input type="hidden" name="input_name" value="input_value" class="my_mdc-select__value" />
</ul>
</div>
</div>
</body>
</html>
This is what I could able to achieve, hope this helps in your implementation. I have not completely implemented the filter logic and all but was able to enter input and display the dropdown simultaneously.
const menuElement = document.querySelector(".mdc-menu");
// const menu = new mdc.menu.MDCMenu(menuElement);
const inputLabel = document.querySelector(".mdc-text-field");
const inputElem = inputLabel.querySelector("input");
const dropdownIcon = document.querySelector(".mdc-select__dropdown-icon");
let isMenuOpen = false;
inputLabel.addEventListener("click", () => {
inputElem.focus();
// menu.open = true;
if (!isMenuOpen) {
menuElement.classList.remove("list-menu-close");
menuElement.classList.add("list-menu-open");
dropdownIcon.classList.add("dropdown-icon-up");
} else {
menuElement.classList.remove("list-menu-open");
menuElement.classList.add("list-menu-close");
dropdownIcon.classList.remove("dropdown-icon-up");
}
isMenuOpen = !isMenuOpen;
});
inputElem.addEventListener("blur", () => {
menuElement.classList.remove("list-menu-open");
menuElement.classList.add("list-menu-close");
dropdownIcon.classList.remove("dropdown-icon-up");
isMenuOpen = false;
});
<div class="dropdown-container">
<label class="mdc-text-field mdc-text-field--filled">
<span class="mdc-text-field__ripple"></span>
<input
class="mdc-text-field__input"
type="text"
aria-labelledby="my-label-id"
/>
<i class="mdc-select__dropdown-icon"></i>
</label>
<div>
<div class="mdc-menu mdc-menu-surface list-menu">
<ul
class="mdc-list"
role="menu"
aria-hidden="true"
aria-orientation="vertical"
tabindex="-1"
>
<li class="mdc-list-item" role="menuitem">
<span class="mdc-list-item__text">A Menu Item</span>
</li>
<li class="mdc-list-item" role="menuitem">
<span class="mdc-list-item__text">Another Menu Item</span>
</li>
</ul>
</div>
</div>
</div>
.dropdown-container {
position: relative;
}
.list-menu {
position: absolute;
top: 60px;
}
.list-menu-open {
display: block;
opacity: 1;
}
.list-menu-close {
display: none;
opacity: 0;
}
.dropdown-icon-up {
transform: rotate(180deg) translateY(-5px);
}
Based on the answers here, I created my own function. Also the Material Design for Web Versions in the answers are quite old. Hope this helps for those looking for something like this.
At first, instead of using MDCSelect, I used MDCTextField and MDCMenu components. I thought everything would be easier this way. It took some time though, but I'm done.
The function that triggers the Menu to open when clicking on the TextField may seem a bit weird. #Zachary Haber explains this,
It appears that the inconsistency is due to a race condition. Clicking
on the menu causes the focus to leave the input which causes the menu
to close. And the menu closing causes focus to move back to the input
making it open again.
The issue is that the menu often closes before the menu has a chance
to send out the selected event.
To review the original answer for MDCMenu click issue: https://stackoverflow.com/a/61965646/5698079
Here is a working example;
const textFields = document.querySelectorAll('.mdc-text-field');
textFields.forEach(field => {
mdc.textField.MDCTextField.attachTo(field);
});
const menuS = document.querySelector("#menu");
const menu = new mdc.menu.MDCMenu(menuS);
const searchFieldS = document.querySelector("#food");
menu.setAnchorCorner(mdc.menuSurface.Corner.BOTTOM_LEFT);
document.querySelectorAll('#menu li').forEach(function(li) {
li.addEventListener('click', function() {
const selectedLi = this.getAttribute("data-value");
if (selectedLi != "notfound") {
// If you are going to post the text field data, I recommend you to get data-value.
searchFieldS.value = selectedLi;
searchFieldS.setAttribute("data-value", selectedLi);
}
});
});
// Open the menu when text field is focused.
(function() {
let menuFocused = false;
searchFieldS.addEventListener("focusin", () => {
if (!menuFocused) menu.open = true;
});
searchFieldS.addEventListener("click", () => {
menu.open = true;
});
menuS.addEventListener("focusin", () => {
menuFocused = true;
});
menuS.addEventListener("focusout", () => {
// This interval is to help make sure that input.focusIn doesn't re-open the menu
setTimeout(() => {
menuFocused = false;
}, 0);
});
searchFieldS.addEventListener("focusout", () => {
setTimeout(() => {
if (!menuFocused) menu.open = false;
}, 0);
});
})();
searchFieldS.addEventListener("keyup", function(e) {
const keyT = event.target.value.toUpperCase();
const menuList = document.querySelectorAll('.mdc-deprecated-list > li > .mdc-deprecated-list-item__text');
const menuLiss = document.querySelectorAll('.mdc-deprecated-list-item');
const noDataEl = document.querySelector("#menuNoData");
//
const arr = [];
menuList.forEach(function(searchItem) {
if (searchItem.parentElement.getAttribute('id') != "menuNoData") {
searchItem.parentElement.dataset.isfound = searchItem.textContent.toUpperCase().includes(keyT) ? "true" : "false";
arr.push(searchItem.parentElement.getAttribute("data-isfound"));
}
});
if (arr.filter(function(countArr) {
return countArr == "true"
}).length == 0) {
noDataEl.classList.remove("hide-none");
} else {
if (!noDataEl.classList.contains("hide-none")) {
noDataEl.classList.add("hide-none");
}
}
});
li[data-isfound="false"] {
display: none;
}
.hide-none {
display: none !important;
}
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script src="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.js"></script>
<link href="https://unpkg.com/material-components-web#latest/dist/material-components-web.min.css" rel="stylesheet">
<div class="mdc-menu-surface--anchor">
<label class="mdc-text-field mdc-text-field--outlined">
<span class="mdc-notched-outline">
<span class="mdc-notched-outline__leading"></span>
<span class="mdc-notched-outline__notch">
<span class="mdc-floating-label" id="my-label-id">Select a fruit..</span>
</span>
<span class="mdc-notched-outline__trailing"></span>
</span>
<input id="food" type="text" class="mdc-text-field__input" aria-labelledby="my-label-id">
</label>
<div id="menu" class="mdc-menu mdc-menu-surface mdc-menu-surface--fullwidth">
<ul class="mdc-deprecated-list" role="listbox" aria-label="Food picker listbox">
<li id="menuNoData" class="mdc-deprecated-list-item mdc-deprecated-list-item--disabled hide-none" aria-selected="false" aria-disabled="true" data-value="notfound" role="option" value="" data-value="">
<span class="mdc-deprecated-list-item__ripple"></span>
<span class="mdc-deprecated-list-item__text">No data found.</span>
</li>
<li class="mdc-deprecated-list-item" aria-selected="false" data-value="grains" role="option">
<span class="mdc-deprecated-list-item__ripple"></span>
<span class="mdc-deprecated-list-item__text">Bread, Cereal, Rice, and Pasta</span>
</li>
<li class="mdc-deprecated-list-item" aria-selected="false" data-value="vegetables" role="option">
<span class="mdc-deprecated-list-item__ripple"></span>
<span class="mdc-deprecated-list-item__text">Vegetables</span>
</li>
<li class="mdc-deprecated-list-item" aria-selected="false" data-value="fruit" role="option">
<span class="mdc-deprecated-list-item__ripple"></span>
<span class="mdc-deprecated-list-item__text">Fruit</span>
</li>
</ul>
</div>
</div>
CodePen: https://codepen.io/lastofdead/pen/bGMZPzO

manually replicate bootstraps typehead-show-hint with angular, css, html

Is there a away to replicate bootstraps typehead suggestive hint feature only using angular, html and css. I would like to show the first item of the search results dynamically in the search box!
<body>
<div ng-app="demoApp" ng-controller='demoCtrl'>
<br>
<input type="text" ng-model="search_term" placeholder="search...">
<br>
<div ng-repeat="(index, item) in items | filter:search_term" ng-class="{'is-first' : index == 0}">{{item}}</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<script>
var app = angular.module('demoApp', []);
app.controller('demoCtrl', ['$scope', function($scope) {
$scope.items = [
'Apple',
'Apricot',
'Avocado',
'Banana',
'Bilberry',
'Blackberry',
'Blackcurrant',
'Blueberry',
'Boysenberry',
'Cantaloupe',
'Currant',
'Cherry',
'Cherimoya',
'Cloudberry',
'Coconut',
'Cranberry',
'Damson',
'Date',
'Dragonfruit'
];
}]);
</script>
<style>
/* put any CSS you need here */
.is-first {
color:red;
}
</style>
</body>
Any help appreciated!
My solution in the end, I used ng-change to hide/show a duplicate input box which returned the first item on the search filter:
<body>
<div ng-app="demoApp" ng-controller='demoCtrl'>
<br>
<input class="main" type="text" ng-model="search_term" placeholder="search..." ng-change="showSuggest()">
<br>
<div ng-show="suggestion" class="autocomplete" ng-repeat="(index, item) in items | filter:search_term | limitTo:1">
<input disabled type="text" placeholder=" {{ item }}">
</div>
<div ng-repeat="(index, item) in items | filter:search_term" ng-class="{'is-first' : index == 0}">{{item}}</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5/angular.min.js"></script>
<script>
var app = angular.module('demoApp', []);
app.controller('demoCtrl', ['$scope', function($scope) {
$scope.suggestion = false;
$scope.items = [
'Apple',
'Apricot',
'Avocado',
'Banana',
'Bilberry',
'Blackberry',
'Blackcurrant',
'Blueberry',
'Boysenberry',
'Cantaloupe',
'Currant',
'Cherry',
'Cherimoya',
'Cloudberry',
'Coconut',
'Cranberry',
'Damson',
'Date',
'Dragonfruit'
];
$scope.showSuggest = function(){
if ($scope.search_term.length < 1)
{$scope.suggestion = false}
else {$scope.suggestion = true}
};
}]);
</script>
<style>
/* put any CSS you need here */
.is-first {
color:red;
}
.main{
position: absolute;
top: 10;
left: 10;
z-index: 11;
background: transparent;
}
.autocomplete{
position: absolute;
top: 10;
left: 10;
background: transparent;
z-index: 10;
}
</style>

Wrap column using ng-repeat

I'm using ng-repeat to print an array in my controller. My problem is that i want my repeat to start listing from the top after my n:th item, like this:
Item 1 Item 6 Item 11
Item 2 Item 7 Item 12
Item 3 Item 8 Item 13
Item 4 Item 9 Item 14
Item 5 Item 10 Item 15
My code:
HTML
<div class="participant-list" >
<div class="participant" ng-repeat="speaker in participants | orderBy:'name'" ng-click="addSpeaker(speaker.id)">{{speaker.name}}, {{speaker.city}}</div>
</div>
CSS
.participant-list {
height: 800px;
}
.participant {
margin: 5px 0px;
padding: 2px 0px;
cursor: pointer;
}
Is there any good way to do this?
It is not the most elegant solution, but it works. It does not work if the number of items is not a multiple of three (or however many columns you want). To fix that you could add blank items to the array. You will also have to sort it in the controller manually.
index.html
<!DOCTYPE html>
<html ng-app="app">
<head>
<title>NG Repeat Column Wrapping</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.min.js"></script>
<script src="./ctrl.js"></script>
</head>
<body ng-controller="ctrl">
<div class="container">
<div class="row" ng-repeat="x in rowsCount">
<div class="col-sm-4">
<span>{{ names[$index] }}</span>
</div>
<div class="col-sm-4">
<span>{{ names[$index + 5] }}</span>
</div>
<div class="col-sm-4">
<span>{{ names[$index + 10] }}</span>
</div>
</div>
</div>
</body>
</html>
ctrl.js
var app = angular.module('app', []);
app.controller('ctrl', function($scope) {
$scope.names = ["Bob", "Susan", "Mark", "John", "Billy", "Ted", "Marcy", "Wilma", "Jeff", "Yasmin", "Pete", "Taylor", "Matthew", "Laney", "Jesus"];
$scope.rowsCount = [];
$scope.createRows = function() {
for (var i = 0; i < ($scope.names.length / 3); i++) {
$scope.rowsCount.push(i);
}
};
$scope.createRows();
});