Does angular ui select (bootstrap version) support optgroup? - angular-ui

Does anyone know if Angular-Ui-Select Bootstrap version support an optgroup?
Can't seem to find any documentation for that on https://github.com/angular-ui/ui-select?
Here is their example:
plnkr.co/edit/QCwSM75ilH2Vh6D9aMA4?p=preview
How to add an optgroup?
In this example, lets say, group persons by countries.

You can use group-by attribute.
See "Demo Multiselect" (last example "Array of objects (with groupBy)") at
https://github.com/angular-ui/ui-select
It's multiselect demo, but group-by works for single select too.

This is group-by using string
app.js:
$scope.countries = [
{
"code": "AD",
"name": "Andorra",
"continent": "Europe"
},
{
"code": "AE",
"name": "United Arab Emirates",
"continent": "Asia"
},
{
"code": "AF",
"name": "Afghanistan",
"continent": "Asia"
}
];
html:
<div>
<label>COUNTRY</label><br>
<ui-select ng-model="user.country" style="min-width: 300px;">
<ui-select-match placeholder="Select Country">
<span ng-bind="$select.selected.name"></span>
</ui-select-match>
<ui-select-choices repeat="country in countries | filter: {name: $select.search}" group-by="'continent'">
<span ng-bind="country.name"></span>
</ui-select-choices>
</ui-select>
</div>
Generated JSON of all countries with their continent using
http://peric.github.io/GetCountries/

Related

How to create a recursive form with Angular 8?

I need to create a dynamic form with multiple nested items. I've found this example
but i'm not sure it's doing deep recursive since once i've tried to add more levels of nested items - the ui brakes down.
Here is the default json structure with my attempts :
{
key: "common",
title: "main fields",
group: [
{
key: "createdAt",
title: "Create Date",
type: "date"
},
// group:[{
// key: "foo",
// title: "Foo",
// type: "select",
// },
// {
// key: "goo",
// title: "Goo",
// type: "input",
// },
// ]
]
},
So as you can see under "common" - i've added 2 more levels of groups - the first group works fine - but the nested group with key "foo" and "goo" it's working.
I'm pretty sure the problem is in the template / markup
<form [formGroup]="filterForm" class="filter-form">
<ng-template #recursiveList let-filterFields let-fromGroup="fromGroup">
<ng-container *ngFor="let item of filterFields">
<ng-container *ngIf="item.group; else default;">
// in this area i'm not sure it's iterate over deeper nesting...
<p>{{item.key}} </p>
<div [formGroupName]="item.key">
<ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit:
item.group, fromGroup: {name: item.key}, isChild:true }"></ng-container>
</div>
</ng-container>
<ng-template #default>
<div class="form-group" [formGroupName]="fromGroup.name">
<input [type]="item.type" [formControlName]="item.key"
[placeholder]="item.title" [name]="item.key" />
</div>
</ng-template>
</ng-container>
</ng-template>
<ng-container *ngTemplateOutlet="recursiveList; context:{ $implicit: filterFields
}">.
From my understanding, there are two issues in the example you provided:
The data structure.
The template.
Data Structure
These are the interfaces I understand from your example:
interface Base {
key: string;
title: string;
}
interface Field extends Base {
type: 'select' | 'input' | 'date' | ...
}
interface Group extends Base {
group: Array<Field | Group>
}
So the JSON example you provided should look something like this:
{
"key": "common",
"title": "main fields",
"group": [
{
"key": "createdAt",
"title": "Create Date",
"type": "date"
},
{
"key": "test",
"title": "Test"
"group": [
{
"key": "foo",
"title": "Foo",
"type": "select"
},
{
"key": "goo",
"title": "Goo",
"type": "input"
}
]
}
]
}
Template
Let's look at a very simplified version of the form:
<form [formGroup]="filterForm">
<ng-container formGroupName="common">
<ng-container *ngTemplateOutlet="control;
context:{ controlName: 'foo', group: 'test' }">
</ng-container>
</ng-container>
<ng-template #control let-group="group" let-controlName="controlName">
<div class="col-md-3">
<div class="form-group" [formGroupName]="group">
<input type="input" [formControlName]="controlName" />
</div>
</div>
</ng-template>
</form>
The code won't work, why? Think about the ng-template as a function. If you want it to know about the formGroupName="common" it needs to be declared within that scope. What matters is the declaration context and not the invocation context, just like regular functions.
This is the working version of the above example:
<form [formGroup]="filterForm">
<ng-container formGroupName="common">
<ng-container *ngTemplateOutlet="control;
context:{ controlName: 'foo', group: 'test' }">
</ng-container>
<ng-template #control let-group="group" let-controlName="controlName">
<div class="col-md-3">
<div class="form-group" [formGroupName]="group">
<input type="input" [formControlName]="controlName" />
</div>
</div>
</ng-template>
</ng-container>
</form>
Things get trickier when you have nested and you need to use recursion.
That's why I think that the approach of using the formGroupName and formControlName directives in this scenario makes things more complicated than they are.
I suggest passing the form control directly into the input by providing the right path to it.
Here is a working example of the idea based on your original example.

Mapping MVC to template using thymeleaf

Teaching myself Spring 5, SpringBoot, and MVC using thymeleaf. It's a simple application. I am working with my controller first to get the view populating correctly before I move to the data access layer.
My issue is the view is not populating with the data that I have created in the Controller.
This is my Controller:
// generates a logger class for you
#Slf4j
#Controller
#RequestMapping("/select")
public class AreaCodeController {
/*
* This method is called BEFORE the #GetMapping method.
* Building a list of items to display on the select template
*/
#ModelAttribute()
public void addAreaToModel(Model model) {
// id, code, country, abbr, provStateLongName, StateCode
List<Area> listing = Arrays.asList(new Area(1000, 123, "US", "AL", "Alabama", StateCode.AL),
new Area(1001, 124, "US", "MS", "Mississippi", StateCode.MS),
new Area(1002, 125, "US", "WA", "Washington", StateCode.WA),
new Area(1003, 126, "US", "WV", "West Virgina", StateCode.WV),
new Area(1004, 127, "US", "GA", "Georgia", StateCode.GA),
new Area(1005, 128, "US", "IL", "Illonis", StateCode.IL),
new Area(1006, 129, "US", "OR", "Oregon", StateCode.OR),
new Area(1007, 121, "US", "CA", "California", StateCode.CA),
new Area(1008, 122, "US", "NV", "Nevada", StateCode.NV),
new Area(1009, 120, "US", "NM", "New Mexico", StateCode.NM),
new Area(1010, 130, "US", "LA", "WildWilly", StateCode.LA));
StateCode[] stateCodes = Area.StateCode.values();
for (StateCode stateCode : stateCodes) {
model.addAttribute("areaCodeList", filterByStateCode(listing, stateCode));
}
}
#GetMapping
public String showSelectForm(Model model) {
model.addAttribute("select", new BusinessNumber());
return "select";
}
private List<Area> filterByStateCode(List<Area> listing, StateCode sc)
{
return listing.stream().filter(x -> x.getCode().equals(sc)).collect(Collectors.toList());
}
}
This is my view:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Virtual Business Number Listing</title>
<link rel="stylesheet" th:href="#{/styles.css}" />
</head>
<body>
<h1>List of Available Business Numbers</h1>
<img th:src="#{/images/phone.png}" style="width:200px;height:125px"/>
<form method="POST" th:object="${select}">
<div class="grid">
<div class="area-group" id="abbrs">
<h3>Choose Your Business Number:</h3>
<div th:each="area : ${areaCodeList}">
<input type="checkbox" name="areaCodeList" th:value="{area.id}" />
<span th:text="${area.code}">Area Code</span><br/>
</div>
</div>
<br/>
<input type="Submit" id="submitButton" th:value="Save">
</div>
</form>
</body>
</html>
This is the behavior I am seeing:
Any suggestions would be greatly appreciated.
Thanks,
Russ
After walking through the code I have solved my own error. As painful as it was, it involved several things:
The filterByStateCode method was using the wrong attribute to filter on. It
was always returning empty.
Adding the the same key for the model attribute was overwriting each entry once the filter method was fixed.
The 'select' template was not keying on the create field.
I think your form tag does not know which action to take from the controller so you need to add it this way :
1- in your view : <form method="POST" th:object="${select}" *th:action="#{/something}"*>
2-in your controller : above your method #GetMapping should be #PostMapping(value="/something") cause of your form has a post method creating a new object select

Email markup for EventReservation not working

I'm trying to use the Gmail Email Markup to create an automatic event in Google Calendar. From the official guide, I'm using the below code:
<html>
<body>
<script type="application/ld+json">
{
"#context": "http://schema.org",
"#type": "EventReservation",
"reservationNumber": "IO12345",
"underName": {
"#type": "Person",
"name": "John Smith"
},
"reservationFor": {
"#type": "Event",
"name": "Google I/O 2013",
"startDate": "2017-11-16T08:30:00-08:00",
"location": {
"#type": "Place",
"name": "Moscone Center",
"address": {
"#type": "PostalAddress",
"streetAddress": "800 Howard St.",
"addressLocality": "San Francisco",
"addressRegion": "CA",
"postalCode": "94103",
"addressCountry": "US"
}
}
}
}
</script>
<p>
Dear John, thanks for booking your Google I/O ticket with us.
</p>
<p>
BOOKING DETAILS<br/>
Reservation number: IO12345<br/>
Order for: John Smith<br/>
Event: Google I/O 2013<br/>
Start time: Nov 16th 2017 8:00am PST<br/>
Venue: Moscone Center, 800 Howard St., San Francisco, CA 94103<br/>
</p>
But this is not working. It isn't creating an event. Any idea why? Also, I have add automatic events from Gmail enabled in my Calendar settings. I'm getting other automatic events of flight bookings on my calendar.
Thanks in advance!
Maybe you are using an educational account (school / university). Try it with a regular gmail account.

changing json data into hex colors and applying style to div

I have the following JSON data:
{
"name": "faded",
"artist": "alan walker",
"color": "faded"
},
{
"name": "i love you",
"artist": "omfg",
"color": "143"
},
{
"name": "closer",
"artist": "the chainsmokers",
"color": "c105e2"
},
{
"name": "roses",
"artist": "the chainsmokers",
"color": "205e2"
}
I'm converting hex codes into background-colors, however some of these will not work since colors needs be either a 6-digit (#ffffff) or 3-digit number (#fff).
A solution would be to add 0 before numbers which are 2,4 or 5 digits only, so "205e2" would come out as "#0205e2". I'd also like to apply this JSON data to each div:
<div style="background-color: #000;"> <!-- background-color here -->
<h1 id="name"></h1> <!-- name goes here -->
<h2 id="artist"></h2> <!-- artist goes here -->
<h3 id="hex">#000000</h3><!-- color text goes here -->
<div class="content">
<button>Like</button>
<button>Copy</button>
</div>
What would be the possible way to code this?

Creating custom Handlebars helper with Mandrill?

Is there a way to define a custom Handlebars helper with Mandrill? Say that I've got an object and the currency is in cents.
"products": [
{
"sku": "hdrPhotos",
"price": 19000,
"title": "Unlimited HDR Photography"
},
{
"sku": "panos",
"price": 2500,
"title": "Panoramas / Virtuals"
},
{
"sku": "fullVideo",
"price": 43000,
"title": "Full Video"
},
{
"sku": "aerialDaytimePhotos",
"price": 17500,
"title": "Aerial Daytime Photography"
},
]
I've got this template:
<!-- BEGIN PRODUCT LOOP // -->
{{#each products}}
<tr class="item">
<td valign="top" class="textContent">
<h4 class="itemName">{{title}}</h4>
<span class="contentSecondary">${{toCurrency price}}</span>
<br/>
<span class="contentSecondary sku"><em>{{sku}}</em></span>
<br/>
</td>
</tr>
{{/each}}
I want to take price, which is in cents, and write a custom helper toCurrency that simply divides it by 100.
Custom helpers are easy enough to do in standard Handlebars, but is it possible with Mandrill's utilization of it?
According to the documentation this isn't possible :
"Use Handlebars regardless of whether you're using templates in Mandrill. We'll cover the basics of Handlebars, helpers implemented specifically for Mandrill, and some deviations from and additions to standard Handlebars."
Reference: https://mandrill.zendesk.com/hc/en-us/articles/205582537-Using-Handlebars-for-Dynamic-Content#using-helpers
There are not even all helpers from handlebar.

Resources