I've been attempting multiple combinations of operators and can't quite get the output I want. Give an array of events:
const events = [
{ day: 1, title: 'Event 1' },
{ day: 1, title: 'Event 2' },
{ day: 1, title: 'Event 3' },
{ day: 2, title: 'Event 4' },
{ day: 2, title: 'Event 5' },
{ day: 2, title: 'Event 6' },
{ day: 'both', title: 'Sandbox 1' },
{ day: 'both', title: 'Sandbox 2' },
]
I'd like an output like so:
[
[
{
"day": 1,
"title": "Event 1"
},
{
"day": 1,
"title": "Event 2"
},
{
"day": 1,
"title": "Event 3"
}
],
[
{
"day": 2,
"title": "Event 4"
},
{
"day": 2,
"title": "Event 5"
},
{
"day": 2,
"title": "Event 6"
}
],
[
{
"day": "both",
"title": "Shared 1"
},
{
"day": "both",
"title": "Shared 2"
}
]
]
The only way I've been able to get this is by subscribing and pushing the result into another array. Ideally the rx chain would build it before subscribing, but I can't quite get it.
Here's what I have that outputs the result above:
from(events).pipe(
groupBy(obj => obj.day),
mergeMap(group => group.pipe(toArray())),
).subscribe(next => {
this.all.push(next)
console.log(this.all)
})
To accumulate the groups into an outer array, you can use another toArray operator after the mergeMap:
from(events).pipe(
groupBy(obj => obj.day),
mergeMap(group => group.pipe(toArray())),
toArray(),
).subscribe(results => console.log(results))
The resultant observable will emit only once and will emit a single array containing all of the group arrays.
Related
Having an observable emitting a list of users with the next content:
[
{
"id": 1,
"name": "John",
"status": "Active"
},
{
"id": 2,
"name": "Mary",
"status": "Inactive"
},
{
"id": 3,
"name": "Peter",
"status": "Inactive"
},
{
"id": 4,
"name": "Susan",
"status": "Active"
}
]
And I have another observable returning the extended user data:
{
"id": 1,
"authorizations: 20
}
I use the detail of each user in an specific details page, but I would like to combine part of the detail in the users list and obtain the next result and only filter by the status Active:
[
{
"id": 1,
"name": "John",
"status": "Active",
"authorizations": 20
},
{
"id": 4,
"name": "Susan",
"status": "Active",
"authorizations": 10
}
]
It is possible to use some filtering operator and combine those results without use two subscriptions?
Tried the following code but, would be a better or simplified way to do it?
import { of, Observable, combineLatest } from 'rxjs';
import { filter, map, mergeAll, mergeMap } from 'rxjs/operators';
type State = 'Active' | 'Inactive';
type User = { id: number; name: string; status: State };
type UserDetail = { id: number; authorizations: number };
type UserWithAuthorizations = User & UserDetail
const users: User[] = [
{
"id": 1,
"name": "John",
"status": "Active"
},
{
"id": 2,
"name": "Mary",
"status": "Inactive"
},
{
"id": 3,
"name": "Peter",
"status": "Inactive"
},
{
"id": 4,
"name": "Susan",
"status": "Active"
}
]
const authorizations: UserDetail[] = [
{ id: 1, authorizations: 20 },
{ id: 2, authorizations: 5 },
{ id: 3, authorizations: 30 },
{ id: 4, authorizations: 10 },
];
const getAuthorizationsByUser= (userId: number): Observable<Partial<UserWithAuthorizations>> => {
const users$ = of(users)
const authorizations$ = of(authorizations)
return combineLatest([users$, authorizations$]).pipe(
map(res => {
const user = res[0].find(u => u.id === userId)
const { authorizations } = res[1].find(a => a.id === userId)
return {
...user,
authorizations
}
}))
};
const fetchUsersWithAuthorizations = () => of(users);
fetchUsersWithAuthorizations()
.pipe(
mergeAll<User>(),
filter((user) => user.status === "Active"),
mergeMap((user) => getAuthorizationsByUser(user.id))
)
.subscribe(console.log);
Why not do it all in a single combine latest?
const { of, map, combineLatest } = rxjs;
const users = [
{
"id": 1,
"name": "John",
"status": "Active"
},
{
"id": 2,
"name": "Mary",
"status": "Inactive"
},
{
"id": 3,
"name": "Peter",
"status": "Inactive"
},
{
"id": 4,
"name": "Susan",
"status": "Active"
}
]
const authorizations = [
{ id: 1, authorizations: 20 },
{ id: 2, authorizations: 5 },
{ id: 3, authorizations: 30 },
{ id: 4, authorizations: 10 },
];
const users$ = of(users)
const authorizations$ = of(authorizations)
const activeUsersWithAuthorizations$ = combineLatest([users$, authorizations$]).pipe(
map(([users, authorizations]) =>
users
.filter((user) => user.status === 'Active')
.map((user) => ({
...user,
authorizations: authorizations.find((a) => a.id === user.id)?.authorizations,
}))
)
);
activeUsersWithAuthorizations$.subscribe(activeUsersWithAuthorizations => {
console.log(activeUsersWithAuthorizations);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.8.0/rxjs.umd.min.js" integrity="sha512-v0/YVjBcbjLN6scjmmJN+h86koeB7JhY4/2YeyA5l+rTdtKLv0VbDBNJ32rxJpsaW1QGMd1Z16lsLOSGI38Rbg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
I have a jsgrid gride and I want to activate edit mode in next line after hit enter key (or arrow down key) in "inline edition" and focus on the same column but next line, as Excel -like keyboard navigation.
The only achievement is to fire update with enter key but how to activate edition in the next line in the same column?
var clients = [
{ "Name": "Otto Clay", "Age": 25, "Country": 1, "Address": "Ap #897-1459 Quam Avenue", "Married": false },
{ "Name": "Connor Johnston", "Age": 45, "Country": 2, "Address": "Ap #370-4647 Dis Av.", "Married": true },
{ "Name": "Lacey Hess", "Age": 29, "Country": 3, "Address": "Ap #365-8835 Integer St.", "Married": false },
{ "Name": "Timothy Henson", "Age": 56, "Country": 1, "Address": "911-5143 Luctus Ave", "Married": true },
{ "Name": "Ramona Benton", "Age": 32, "Country": 3, "Address": "Ap #614-689 Vehicula Street", "Married": false }
];
var countries = [
{ Name: "", Id: 0 },
{ Name: "United States", Id: 1 },
{ Name: "Canada", Id: 2 },
{ Name: "United Kingdom", Id: 3 }
];
$("#jsGrid").jsGrid({
width: "100%",
height: "400px",
inserting: false,
editing: true,
sorting: true,
paging: true,
data: clients,
fields: [
{ name: "Name", type: "text", width: 150, validate: "required" },
{ name: "Age", type: "number", width: 50 },
{ name: "Address", type: "text", width: 200 },
{ name: "Country", type: "select", items: countries, valueField: "Id", textField: "Name" },
{ name: "Married", type: "checkbox", title: "Is Married", sorting: false },
{ type: "control" }
],
onError: function (args) {
console.log("ERR");
console.log(args);
},
});
$('#jsGrid').off().on('keydown', 'input[type=text], input[type=number]', (event) => {
if (event.which === 13) { // Detect enter keypress
$('#jsGrid').jsGrid("updateItem"); // Update the row
}
});
UPDATE: I developed an alternative that use Enter (or arrow down key) con updateitem, activate the edit mode in the next row and focus on the same previous column control. But I think there is an easy way.
var LastIndexInputs = -1;
var LastIndexSelect = -1;
function ActivateEditNextLine(NewIndex) {
var gridBody = $("#jsGrid").find('.jsgrid-grid-body');
gridBody.find('.jsgrid-table tr').each(function (index, tr) {
if (index == NewIndex) {
$(tr).trigger('click');
RowTarget = gridBody.find(".jsgrid-edit-row");
if (LastIndexInputs != -1) {
RowTarget.find('.Campo')[LastIndexInputs].focus();
RowTarget.find('.Campo')[LastIndexInputs].select();
}
else {
if (LastIndexSelect != -1) {
RowTarget.find('select')[LastIndexSelect].focus();
}
}
}
});
};
var clients = [
{ "Name": "Otto Clay", "Age": 25, "Country": 1, "Address": "Ap #897-1459 Quam Avenue", "Married": false },
{ "Name": "Connor Johnston", "Age": 45, "Country": 2, "Address": "Ap #370-4647 Dis Av.", "Married": true },
{ "Name": "Lacey Hess", "Age": 29, "Country": 3, "Address": "Ap #365-8835 Integer St.", "Married": false },
{ "Name": "Timothy Henson", "Age": 56, "Country": 1, "Address": "911-5143 Luctus Ave", "Married": true },
{ "Name": "Ramona Benton", "Age": 32, "Country": 3, "Address": "Ap #614-689 Vehicula Street", "Married": false }
];
var countries = [
{ Name: "", Id: 0 },
{ Name: "United States", Id: 1 },
{ Name: "Canada", Id: 2 },
{ Name: "United Kingdom", Id: 3 }
];
$("#jsGrid").jsGrid({
width: "100%",
height: "400px",
inserting: false,
editing: true,
sorting: true,
paging: true,
data: clients,
fields: [
{ name: "Name", type: "text", width: 150, validate: "required" },
{ name: "Address", type: "text", width: 200 },
{ name: "Country", type: "select", items: countries, valueField: "Id", textField: "Name" },
{ name: "Age", type: "text", width: 50 },
{ name: "Married", type: "checkbox", title: "Is Married", sorting: false },
{ type: "control" },
],
onItemUpdating: function (args) {
console.log("confirm edition");
// pointer to last control index for jump to the same colum
var gridBody = $("#jsGrid").find('.jsgrid-grid-body');
Registro = gridBody.find(".jsgrid-edit-row");
var inputs = Registro.find('.Campo');
LastIndexInputs = inputs.index(inputs.filter(':focus'))
var selects = Registro.find('select');
LastIndexSelect = selects.index(selects.filter(':focus'))
},
onItemUpdated: function (args) {
if (args.grid.data.length != (args.itemIndex + 1)) {
ActivateEditNextLine(args.itemIndex + 1);
}
},
editItem: function (item) {
console.log("Enter in edition mode")
var $row = this.rowByItem(item);
if ($row.length) {
//console.log('$row: ' + JSON.stringify($row));
this._editRow($row);
}
},
onError: function (args) {
console.log("ERR");
console.log(args);
},
});
$('#jsGrid').off().on('keydown', 'input[type!=hidden], select', (event) => {
if (event.which === 13) { // Detect enter keypress
$('#jsGrid').jsGrid("updateItem"); // Update the row
}
if (event.which === 40) { // arrow down keypress
$('#jsGrid').jsGrid("updateItem"); // Update the row
}
});
I have this TKEntityProperty:
<TKEntityProperty v-tkDataFormProperty name="groups" displayName="Groups" index="2" :valuesProvider="retrieveGroups">
and this gets values from below object:
retrieveGroups:[
{key: "1", "label": "Group 1"},
{key: "2", "label": "Group 2"},
{key: "3", "label": "Group 3"}
]
but it does not multi select. I want to select multiple elements.
Is there another type of editor available ?
As #Manoj suggested, you should use AutoCompleteInline
Here is an example, it is available at Nativescript github page
data() {
return {
title: description,
booking: new Booking(),
bookingMetadata: {
'isReadOnly': false,
'commitMode': DataFormCommitMode.Immediate,
'validationMode': DataFormValidationMode.Immediate,
'propertyAnnotations': [{
'name': 'from',
'displayName': 'From:',
'index': 0,
'editor': DataFormEditorType.AutoCompleteInline,
'editorParams': {
'autoCompleteDisplayMode': AutoCompleteDisplayMode.Tokens
},
'valuesProvider': fromProviders,
},
{
'name': 'to',
'displayName': 'To:',
'index': 1,
'editor': DataFormEditorType.AutoCompleteInline,
'editorParams': {
'autoCompleteDisplayMode': AutoCompleteDisplayMode.Plain
},
'valuesProvider': ['New York', 'Washington', 'Los Angeles'],
},
]
}
};
},
i have the following response from my controller
[
{
"id": 1,
"place_id": 1,
"name": "Test",
"type": 5,
"created_at": "2018-06-04 15:29:02",
"updated_at": "2018-06-04 15:29:02",
"time": [
{
"id": 1,
"stadium_id": 1,
"day": "Saturday",
"from_hour": 7,
"to_hour": 12,
"created_at": "2018-06-04 15:29:42",
"updated_at": "2018-06-04 15:29:42"
},
{
"id": 2,
"stadium_id": 1,
"day": "Sunday",
"from_hour": 7,
"to_hour": 12,
"created_at": "2018-06-04 15:54:03",
"updated_at": "2018-06-04 15:54:03"
}
]
}
]
i want to access the day attribute in each time object
i tried the code below but of course it just loads the first result
is there a solution
columns: [
{ data: 'name' },
{ data: 'type' },
{ data: 'time.0.day' },
{ data: 'time.0.from_hour' },
{ data: 'time.0.to_hour' },
],
You can actually access time array by using the render property:
columns: [{
data: 'name'
},
{
data: 'type'
},
{
data: 'time',
render: function(data, type, row) {
var txt = '';
data.forEach(function(item) {
if (txt.length > 0) {
txt += '</br> '
}
txt += item.day;
});
return txt;
}
},
...
This would just add a line break for every objects in time. Here's a Fiddle for you to examine.
so i am looking into loading external data in an select2 box where there is prepopulate results from the json
i have two issue - getting the data in and then only loading the first few but when a user searches it passes the request to the rest and then the specific json is returned
so the HTML is a simple as
<input type="hidden" id="e21" style="width:300px;"/>
the inital js is
$(document).ready(function () {
$('#e21').select2({
query: function (query){
var data = {results: []};
console.log(data);
$.each(preload_data, function(){
if(query.term.length == 0 || this.text.toUpperCase().indexOf(query.term.toUpperCase()) >= 0 ){
data.results.push({id: this.id, text: this.text });
}
});
query.callback(data);
}
});
$('#e21').select2('data', preload_data );
});
what that does is load in preload_data so that could be
var preload_data = [
{ id: 'user0', text: 'Disabled User'},
{ id: 'user1', text: 'Jane Doe'},
{ id: 'user2', text: 'John Doe', locked: true },
{ id: 'user3', text: 'Robert Paulson', locked: true },
{ id: 'user5', text: 'Spongebob Squarepants'},
{ id: 'user6', text: 'Planet Bob' },
{ id: 'user7', text: 'Inigo Montoya' }
];
an example is here
http://jsfiddle.net/dwhitmarsh/MfJ4B/10/
but instead of preload_data i want to load in load in a ajax call and pass the results
so i could use
var preload_data = $.ajax({
url: 'data/more.json',
method: 'get',
dataType: 'json'
});
but need to wait for the json to load and only want to load in the first 10.
then when a user actually searches i want to pass extra variables like
string: term, //search term
page_limit: 10, // page size
page: page // page number
page is part of the select 2
can anyone help?
btw the more.json looks like
{
"total": 8,
"result": [{
"id": "1",
"label": "Type",
"safeName":"type",
"jsonFile": "type.json"
},{
"id": "2",
"label": "Primary Applicant Name",
"safeName":"primaryApplicantName",
"jsonFile": "primary.json"
},{
"id": "3",
"label": "Address",
"safeName":"address",
"jsonFile": "address.json"
},{
"id": "4",
"label": "Product",
"safeName":"product",
"jsonFile": "product.json"
},{
"id": "5",
"label": "Verification",
"safeName": "verification",
"jsonFile": "verification.json"
},{
"id": "6",
"label": "Documents",
"safeName": "documents",
"jsonFile": "documents.json"
},{
"id": "7",
"label": "Suburb",
"safeName": "suburb",
"jsonFile": "suburb.json"
},{
"id": "8",
"label": "State",
"safeName": "state",
"jsonFile": "state.json"
}]
}