Pagination error on Gatsby JS category and tag pages - gatsby-plugin

I use the awesome paginate plugin for Gatsby to do pagination on archive pages on the site. The plugin connects to the gatsby-node file.js is called there with the help of such code
paginate({
createPage,
items: allMdx.edges,
itemsPerPage: 1,
pathPrefix: '/work',
component: path.resolve('src/templates/work.js')
});
Pagination works great on blog and works pages. I created these pages using the Gatsby Route API, without using the createPage function in gatsby-node. Pagination works great on blog and works pages. I created these pages using the Gatsby Route API, without using the createPage function in gatsby-node.js . But on the pages of tags and categories, I can't enable pagination. These pages were created using createPage. Below I present the code of my gatsby-node.js
const _ = require("lodash")
//const readingTime = require("reading-time")
const { paginate } = require('gatsby-awesome-pagination')
const path = require("path")
const { transliterate } = require('./src/functions/transletter')
const { createFilePath } = require('gatsby-source-filesystem')
/* Create category page */
function dedupeCategories(allMdx) {
const uniqueCategories = new Set()
// Iterate over all articles
allMdx.edges.forEach(({ node }) => {
// Iterate over each category in an article
node.frontmatter.categories.forEach(category => {
uniqueCategories.add(category)
})
})
// Create new array with duplicates removed
return Array.from(uniqueCategories)
}
/* Create tag page */
function dedupeTags(allMdx) {
const uniqueTags = new Set()
// Iterate over all articles
allMdx.edges.forEach(({ node }) => {
// Iterate over each category in an article
node.frontmatter.tags.forEach(tag => {
uniqueTags.add(tag)
})
})
// Create new array with duplicates removed
return Array.from(uniqueTags)
}
exports.createPages = async ({ graphql, actions, reporter }) => {
const { createPage } = actions
// Query markdown files including data from frontmatter
const {
data: { allMdx },
} = await graphql(`
query {
allMdx (filter: {frontmatter: {type: {in: "blog"}}}){
edges {
node {
id
frontmatter {
categories
tags
slug
}
fields {
slug
}
}
}
}
}
`)
// Create array of every category without duplicates
const dedupedCategories = dedupeCategories(allMdx)
// Iterate over categories and create page for each
dedupedCategories.forEach(category => {
reporter.info(`Creating page: blog/category/${category}`)
createPage({
path: `blog/category/${_.kebabCase(transliterate(category))}`,
component: require.resolve("./src/templates/categories.js"),
// Create props for our CategoryList.js component
context: {
category,
// Create an array of ids of articles in this category
ids: allMdx.edges
.filter(({ node }) => {
return node.frontmatter.categories.includes(category)
})
.map(({node}) => node.id),
},
})
})
// Create array of every category without duplicates
const dedupedTags = dedupeTags(allMdx)
// Iterate over categories and create page for each
dedupedTags.forEach(tag => {
reporter.info(`Creating page: blog/tag/${tag}`)
createPage({
path: `blog/tag/${_.kebabCase(transliterate(tag))}`,
component: require.resolve("./src/templates/tags.js"),
// Create props for our CategoryList.js component
context: {
tag,
// Create an array of ids of articles in this category
ids: allMdx.edges
.filter(({ node }) => {
return node.frontmatter.tags.includes(tag)
})
.map(({node}) => node.id),
},
})
})
/* It's creating a new page for each post. */
paginate({
createPage,
items: allMdx.edges,
itemsPerPage: 1,
pathPrefix: '/blog',
component: path.resolve('src/templates/blog.js')
});
/* It's creating a new page for each post. */
paginate({
createPage,
items: allMdx.edges,
itemsPerPage: 1,
pathPrefix: '/work',
component: path.resolve('src/templates/work.js')
});
/* It's creating a new page for each post. */
paginate({
createPage,
items: allMdx.edges,
itemsPerPage: 1,
pathPrefix: '/blog/category',
component: path.resolve('src/templates/categories.js')
});
}
/* Creating a slug for each post. */
exports.onCreateNode = ({ node, actions, getNode }) => {
const { createNodeField } = actions;
if (node.internal.type === `Mdx`) {
const value = createFilePath({ node, getNode });
createNodeField({
name: 'slug',
node,
value,
});
}
};
/* It's creating a new field in the GraphQL schema called `relatedPosts` that returns an array of Mdx
nodes. */
exports.createResolvers = ({ createResolvers }) => {
const resolvers = {
Mdx: {
relatedPosts: {
type: ['Mdx'],
resolve: (source, args, context, info) => {
return context.nodeModel.runQuery({
query: {
filter: {
id: {
ne: source.id,
},
frontmatter: {
// type: {
// ne: source.frontmatter.type === `work`,
// },
tags: {
in: source.frontmatter.tags,
},
},
},
},
type: 'Mdx',
})
},
},
},
}
createResolvers(resolvers)
}
And this is the template code of my category src/templates/category.js
import React from "react"
import { Link, graphql } from "gatsby"
import Layout from '../components/layout'
import Seo from '../components/seo'
import Pager from '../components/pagination'
const CategoryList = ({ pageContext: { category }, data: { allMdx }, pageContext }) =>
(
<Layout pageTitle={category}>
{
allMdx.edges.map(({ node }) => {
return (
<article key={node.id}>
<h2>
<Link to={`/blog${node.fields.slug}`}>
{node.frontmatter.title}
</Link>
</h2>
<p>Posted: {node.frontmatter.date}</p>
<p>{node.excerpt}</p>
</article>
)
})
}
<Pager pageContext={pageContext} />
</Layout>
)
export const query = graphql`
query CategoryListQuery($ids: [String]!, $limit: Int!, $skip: Int!) {
allMdx (filter: { id: { in: $ids }, frontmatter: {type: {in: "blog"}}}, limit: $limit,
skip: $skip) {
edges {
node {
frontmatter {
title
date(formatString: "MMMM DD, YYYY")
}
fields {
slug
}
id
excerpt
}
}
}
}
`
export const Head = ({ pageContext }) => (
<Seo
title={pageContext.category}
description={`Статьи из категории ${pageContext.category}`}
/>
)
export default CategoryList
The Pager component looks like this
import React from 'react';
import { Link } from 'gatsby';
const Pager = ({ pageContext }) => {
const { previousPagePath, nextPagePath } = pageContext;
return (
<nav style={{ display: 'flex', justifyContent: 'space-between' }}>
<div>
{previousPagePath && (
<Link to={previousPagePath}>
<button>← Newer Posts</button>
</Link>
)}
</div>
<div style={{ justifySelf: 'flex-end' }}>
{nextPagePath && (
<Link to={nextPagePath}>
<button>Older Posts →</button>
</Link>
)}
</div>
</nav>
);
};
export default Pager;
This is errors
ERROR #85920 GRAPHQL
There was an error in your GraphQL query:
Variable "$limit" of required type "Int!" was not provided.
> 1 | query CategoryListQuery($ids: [String]!, $limit: Int!, $skip: Int!) {
| ^
2 | allMdx(
3 | filter: {id: {in: $ids}, frontmatter: {type: {in: "blog"}}}
4 | limit: $limit
5 | skip: $skip
6 | ) {
7 | edges {
8 | node {
9 | frontmatter {
10 | title
11 | date(formatString: "MMMM DD, YYYY")
File path: C:/gatsby/schtml/src/templates/categories.js
Url path: /blog/category/gatsby-js
Plugin: none
Suggestion 1:
If you're not using a page query but a useStaticQuery / StaticQuery you see this error because they currently don't support
variables. To learn more about the limitations of useStaticQuery / StaticQuery, please visit these docs:
https://www.gatsbyjs.com/docs/how-to/querying-data/use-static-query/
https://www.gatsbyjs.com/docs/how-to/querying-data/static-query/
Suggestion 2:
You might have a typo in the variable name "$limit" or you didn't provide the variable via context to this page query. Have a look
at the docs to learn how to add data to context:
https://www.gatsbyjs.com/docs/how-to/querying-data/page-query#how-to-add-query-variables-to-a-page-query
ERROR #85920 GRAPHQL
There was an error in your GraphQL query:
Variable "$skip" of required type "Int!" was not provided.
> 1 | query CategoryListQuery($ids: [String]!, $limit: Int!, $skip: Int!) {
| ^
2 | allMdx(
3 | filter: {id: {in: $ids}, frontmatter: {type: {in: "blog"}}}
4 | limit: $limit
5 | skip: $skip
6 | ) {
7 | edges {
8 | node {
9 | frontmatter {
10 | title
11 | date(formatString: "MMMM DD, YYYY")
File path: C:/gatsby/schtml/src/templates/categories.js
Url path: /blog/category/gatsby-js
Plugin: none
Suggestion 1:
If you're not using a page query but a useStaticQuery / StaticQuery you see this error because they currently don't support
variables. To learn more about the limitations of useStaticQuery / StaticQuery, please visit these docs:
https://www.gatsbyjs.com/docs/how-to/querying-data/use-static-query/
https://www.gatsbyjs.com/docs/how-to/querying-data/static-query/
Suggestion 2:
You might have a typo in the variable name "$skip" or you didn't provide the variable via context to this page query. Have a look at the docs to learn how to add data to context:
https://www.gatsbyjs.com/docs/how-to/querying-data/page-query#how-to-add-query-variables-to-a-page-query
ERROR #85920 GRAPHQL
There was an error in your GraphQL query:
Variable "$limit" of required type "Int!" was not provided.
> 1 | query CategoryListQuery($ids: [String]!, $limit: Int!, $skip: Int!) {
| ^
2 | allMdx(
3 | filter: {id: {in: $ids}, frontmatter: {type: {in: "blog"}}}
4 | limit: $limit
5 | skip: $skip
6 | ) {
7 | edges {
8 | node {
9 | frontmatter {
10 | title
11 | date(formatString: "MMMM DD, YYYY")
File path: C:/gatsby/schtml/src/templates/categories.js
Url path: /blog/category/gatsby-develop
Plugin: none
Suggestion 1:
If you're not using a page query but a useStaticQuery / StaticQuery you see this error because they currently don't support
variables. To learn more about the limitations of useStaticQuery / StaticQuery, please visit these docs:
https://www.gatsbyjs.com/docs/how-to/querying-data/use-static-query/
https://www.gatsbyjs.com/docs/how-to/querying-data/static-query/
Suggestion 2:
You might have a typo in the variable name "$limit" or you didn't provide the variable via context to this page query. Have a look
at the docs to learn how to add data to context:
https://www.gatsbyjs.com/docs/how-to/querying-data/page-query#how-to-add-query-variables-to-a-page-query
ERROR #85920 GRAPHQL
There was an error in your GraphQL query:
Variable "$skip" of required type "Int!" was not provided.
> 1 | query CategoryListQuery($ids: [String]!, $limit: Int!, $skip: Int!) {
| ^
2 | allMdx(
3 | filter: {id: {in: $ids}, frontmatter: {type: {in: "blog"}}}
4 | limit: $limit
5 | skip: $skip
6 | ) {
7 | edges {
8 | node {
9 | frontmatter {
10 | title
11 | date(formatString: "MMMM DD, YYYY")
File path: C:/gatsby/schtml/src/templates/categories.js
Url path: /blog/category/gatsby-develop
Plugin: none
Suggestion 1:
If you're not using a page query but a useStaticQuery / StaticQuery you see this error because they currently don't support
variables. To learn more about the limitations of useStaticQuery / StaticQuery, please visit these docs:
https://www.gatsbyjs.com/docs/how-to/querying-data/use-static-query/
https://www.gatsbyjs.com/docs/how-to/querying-data/static-query/
Suggestion 2:
You might have a typo in the variable name "$skip" or you didn't provide the variable via context to this page query. Have a look at the docs to learn how to add data to context:
https://www.gatsbyjs.com/docs/how-to/querying-data/page-query#how-to-add-query-variables-to-a-page-query
success Writing page-data.json files to public directory - 0.044s - 2/2 45.97/s
success run page queries - 0.422s - 3/3 7.12/s
success Writing page-data.json files to public directory - 0.059s - 3/3 50.83/s

Related

Nunjucks nested object array field printing

My array data:
data = [
{ field: { name:"name1", title:"title1" } },
{ field: { name:"name2", title:"title2" } },
{ field: { name:"name3", title:"title3" } }
];
I want to write name fields like this:
Expected Output
name1.name2.name3
I need join these object's specified field values but I don't know how to get them like this.
What I tried and failed =>
data | selectattr("field") | selectattr("name") | join(".") }}
selectattr-filter only filter data elements. Therefore, when you apply selectattr('name'), nunjucks try to filter data by elements having name-field (none of them) and returns the empty result.
The simplest way to achive name1.name2.name3 is to use a custom filter
const nunjucks = require('nunjucks');
const env = nunjucks.configure();
env.addFilter('map', function (arr, prop, ...etc) {
const f = typeof prop == 'function' ?
prop : typeof env.filters[prop] == 'function' ?
env.filters[prop] : (e) => e[prop];
return arr instanceof Array && arr.map(e => f(e, ...etc)) || arr;
});
const data = [
{field: {name: "name1", title: "title1"}},
{field: {name: "name2", title: "title2"}},
{field: {name: "name3", title: "title3"}}
];
const html = env.renderString(`{{ data | map('field') | map('name') | join('.') }}`, {data});
console.log(html);

vue apollo composite oe batch queries -- possible?

Has anyone found away of doing composite queries with Vue Apollo (Apollo boost)?
A composite batch query
I have an array if ids [ 12, 34, 56, 76, 76, …] and for each id I need to send a graphQL query. I could end up with a 500 queries being called one after the other.
Instead I want to batch them (or send them all at the same time) using aliases. Something like
[
first: User(id: "12") {
name
email
},
second: User(id: "34") {
name
email
},
....
....
oneHundred: User(id: "34") {
name
email
}
]
With the results being popped into an array. E.g.
this.users.pop(second)
I’ve done a fair bit of reading and searching. I found this that hints that it can be done
enter link description here
Any help out there?
The answer is in 3 parts.
Does the server recognise batch requests? Apollo server does by default
Set up the client in your app to handle batches
Create the queries on the fly.
Creating a Vue Apollo client:
import VueApollo from 'vue-apollo'
import Vue from 'vue';
import { ApolloClient } from 'apollo-client'
import { ApolloLink, split } from 'apollo-link'
import { HttpLink } from 'apollo-link-http'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { BatchHttpLink } from 'apollo-link-batch-http';
import { getMainDefinition } from 'apollo-utilities'
const httpLink = new HttpLink({ uri: HTTP_END_POINT });
const batchLink = new BatchHttpLink({ uri: HTTP_END_POINT });
const link = split(
// split based on operation type
({ query }) => {
const { kind, operation } = getMainDefinition(query)
return kind === 'OperationDefinition' && operation === 'subscription'
},
httpLink,
batchLink,
)
const client = new ApolloClient({
link: ApolloLink.from([link]),
cache: new InMemoryCache(),
connectToDevTools: true
})
Example of sending of a batch of queries inside a Vue component:
methods: {
fetchUsers() {
[<a list of user ids>].forEach(id => {
this.$apollo.query({
query: USER_QUERY,
variables: { id },
}).then(d => {
console.table(d.data.User)
this.users.push(d.data.User)
}).catch(e => console.log(e));
});
},
}
The actual query looks like:
import gql from "graphql-tag";
export const USER_QUERY = gql`
query User($id: String!) {
User(id: $id) {
firstName
lastName
}
}

how to optimisticResponse a connection property in relay modern mutation?

i have a comments connection in a mutation, this is the query:
export default mutationFromQuery(graphql`
mutation AddBookMutation($input: AddBookInput! $count: Int $cursor: String ) {
addBook(input: $input) {
book {
__typename
cursor
node {
id
title
owner
createdAt
comments(first: $count, after: $cursor)
#connection(key: "BookComments_comments", filters: []) {
__typename
edges {
node {
id
}
}
}
}
}
}
}
`)
This is how i did my optimisticUpdater that don't work:
optimisticUpdater: (store) => {
const userProxy = store.get(viewerId)
const owner = userProxy.getValue('username')
const id = uuidv1();
const book = store.create(id, 'Book');
book.setValue(id, 'id');
book.setValue(bookTitle, 'title');
book.setValue(owner, 'owner');
book.setValue(Date.now(), 'createdAt');
const comments = store.create(uuidv1(), 'comments')
comments.setLinkedRecords([], 'edges')
const pageInfo = store.create(uuidv1(), 'pageInfo')
pageInfo.setValue(null, 'endCursor')
pageInfo.setValue(false, 'hasNextPage')
pageInfo.setValue(false, 'hasPreviousPage')
pageInfo.setValue(null, 'startCursor')
comments.setLinkedRecord(pageInfo, 'pageInfo')
book.setLinkedRecord(comments, 'comments')
const bookEdge = store.create(uuidv1(), 'BookEdge');
bookEdge.setLinkedRecord(book, 'node');
console.log('bookEdge ', bookEdge)
booksUpdater(userProxy, bookEdge);
},
The problem i have is that comments always ends up on undefined as you can see above i've already set it. I also did this but i am still not getting an optimistic UI:
optimisticResponse: {
addBook: {
book: {
__typename: 'BookEdge',
cursor: uuidv1(),
node: {
id: uuidv1(),
title: bookTitle,
owner: username,
createdAt: Date.now(),
comments: {
__typename: 'CommentConnection',
edges: [],
pageInfo: {
endCursor: null,
hasNextPage: false
}
}
}
}
}
},
App don't crash with optimisticResponse code but no optimistic UI effect, but with the optimisticUpdater it's crashing with comments being undefined, for now I am settling with my updater:
updater: (store) => {
const userProxy = store.get(viewerId)
const payload = store.getRootField('addBook');
booksUpdater(userProxy, payload.getLinkedRecord('book'));
},
since the comments is undefined I guess we cannot use this for optimistic effect:
const comments = store.create(uuidv1(), 'comments')
comments.setLinkedRecords([], 'edges')
book.setLinkedRecord(comments, 'comments')
on my Book, this is the query which has the comments fragment that is undefined on optimistic update with the code above:
export default createRefetchContainer(
BookItem,
{
book: graphql`
fragment BookItem_book on Book
#argumentDefinitions(
count: { type: "Int", defaultValue: 5 }
cursor: { type: "String", defaultValue: null }
) {
id
title
owner
createdAt
...BookComments_book
}
`
},
graphql`
query BookItemQuery($id: ID!, $count: Int, $cursor: String) {
book: node(id: $id) {
...BookItem_book #arguments(count: $count, cursor: $cursor)
}
}
`
);
and now the query for the comments component where it gets the book.comments.edges is undefined:
export default createPaginationContainer(
BookComments,
{
book: graphql`
fragment BookComments_book on Book
#argumentDefinitions(
count: { type: "Int", defaultValue: 3 }
cursor: { type: "String", defaultValue: null }
) {
id
title
comments(first: $count, after: $cursor)
#connection(key: "BookComments_comments", filters: []) {
__typename
edges {
node {
id
text
owner
createdAt
}
}
pageInfo {
startCursor
endCursor
hasPreviousPage
hasNextPage
}
}
}
`
},
{
direction: 'forward',
getConnectionFromProps: (props) => props.book && props.book.comments,
getFragmentVariables: (prevVars, totalCount) => ({
...prevVars,
count: totalCount
}),
getVariables: (props, { count, cursor }, _fragmentVariables) => ({
count,
cursor,
id: props.book.id
}),
query: graphql`
query BookCommentsQuery($id: ID!, $count: Int, $cursor: String) {
book: node(id: $id) {
...BookComments_book #arguments(count: $count, cursor: $cursor)
}
}
`
}
);
maybe this is an anti pattern? but i just wanted to have a optimistic effect for this
Some things are still not very clear to me about how those components and queries work, so I'll update this answer later. (I don't know if you want to return new book optimistically from node() query or add it to some list/connection of books)
Please check if I used correct type names (CommentConnection / CommentsConnection, etc)
optimisticUpdater: (store) => {
const userProxy = store.get(viewerId)
const owner = userProxy.getValue('username')
const commentsParams = { // must be same keys and values as in comments(first: $count, after: $cursor)
first: count,
after: cursor
}
// Create Book
const id = uuidv1();
const book = store.create(id, 'Book');
book.setValue(id, 'id');
book.setValue(bookTitle, 'title');
book.setValue(owner, 'owner');
book.setValue(Date.now(), 'createdAt');
// Create comments connection
const comments = store.create(uuidv1(), 'CommentConnection')
comments.setLinkedRecords([], 'edges')
// Create PageInfo
const pageInfo = store.create(uuidv1(), 'PageInfo')
pageInfo.setValue(null, 'endCursor')
pageInfo.setValue(false, 'hasNextPage')
pageInfo.setValue(false, 'hasPreviousPage')
pageInfo.setValue(null, 'startCursor')
// Link created records
comments.setLinkedRecord(pageInfo, 'pageInfo')
book.setLinkedRecord(comments, 'comments', commentsParams) // don't forget commentsParams with same values as are used in comments graphql query
// I'm not sure about this final part, because I don't really get how that app works, but if you want this book to show as optimistic response for `node(id: $id)`, you'll do something like this:
store.getRoot().setLinkedRecord(book, 'node', { id: id }) // same id as used in BookItemQuery
}

How to present sort order-by query in Falcor?

Suppose the model is structured as
{
events: [
{
date: '2016-06-01',
name: 'Children Day'
},
{
date: '2016-01-01',
name: 'New Year Day'
},
{
date: '2016-12-25',
name: 'Christmass'
}
]
}
There could be a lot of events in our storage. From client side, we want to issue a query to get 10 events order by date in ascending order.
How to present this kind of query in Falcor?
Heres what I would do: first, promote your events to entities, i.e. give them ids:
id | date | name
1 | 2016-06-01 | Children Day
2 | 2016-01-01 | New Year Day
3 | 2016-12-25 | Christmass
Then provide a route providing these events by id:
route: 'eventsById[{integers:ids}]["date","name"]'
which returns the original data. Now you can create a new route for orderings
route: 'orderedEvents['date','name']['asc','desc'][{ranges:range}]
which returns references into the eventsById route. This way your client could even request the same data sorted in different ways within the same request!
router.get(
"orderedEvents.date.asc[0..2]",
"orderedEvents.date.desc[0..2]");
which would return
{
'eventsById': {
1: {
'date':'2016-06-01',
'name':'Children Day' },
2: {
'date':'2016-01-01',
'name':'New Year Day' },
3: {
'date':'2016-12-25',
'name':'Christmass' } },
'orderedEvents': {
'date': {
'asc': [
{ '$type':'ref', 'value':['eventsById',2] },
{ '$type':'ref', 'value':['eventsById',1] },
{ '$type':'ref', 'value':['eventsById',3] } ],
'desc': [
{ '$type':'ref', 'value':['eventsById',3] },
{ '$type':'ref', 'value':['eventsById',1] },
{ '$type':'ref', 'value':['eventsById',2] } ] } }
}

get data of a nestet JSONModel into a sap.m.table

i'm trying to display a table (sap.m.table) with 2 columns (Roles, User). the table get its data from a JSONModel
model:
{
"roles":[
{
"id":1,
"name":"Administrator",
"permissions":[
{
"id":1,
"permissionUtilPermission":"CREATE_USER",
"description":"Create User",
"name":"Create User"
}
],
"user":[
{
"loginName":"admin1",
"firstName":"John",
"lastName":"Doe",
"id":1,
"active":true
},
{
"loginName":"admin2",
"firstName":"Carmen",
"lastName":"Stiffler",
"id":2,
"active":true
}
.........
]
},
{
"id":2,
"name":"User",
"permissions":[
],
"user":[
{
"loginName":"user1",
"firstName":"Carlos",
"lastName":"Mayer",
"id":3,
"active":true
},
{
"loginName":"user2",
"firstName":"Jonny",
"lastName":"Jefferson",
"id":4,
"active":true
},
.......
]
}
]
}
in the view i create the table with 2 columns and a ColumnListItem as template.
this template contains a sap.m.Text and a sap.m.FlexBox which have a sap.m.Button as item.
In the first column should be displayed the 'name' of the 'roles'.
In the second column should be displayed the FlexBox within Buttons and the text of these buttons should be the names ('loginName') of the roles user
view:
var oTable = new sap.m.Table('mRoleTable', {
width: '75%',
columns: [new sap.m.Column('', {
header: new sap.ui.commons.Label({
text: '{i18n>admin.RoleTableHeaderRole}'
})
}),
new sap.m.Column('', {
header: new sap.ui.commons.Label({
text: '{i18n>admin.RoleTableHeaderUser}'
})
})],
items: new sap.m.ColumnListItem('oRolesItemTemplateId', {
cells: [new sap.m.Text('item1Id', {
text: '{name}'
}),
new sap.m.FlexBox('item2Id', {
items: new sap.m.Button('userBtnId', {
text: '{user}'
}),
})]
})
});
the onInit function of the controller instantiates a new JSONModel and load the data from the json file. after that the model is set to the table and the items are bind to '/roles'
controller:
onInit: function() {
var oView = this.getView();
var oController = this;
var oModel = new sap.ui.model.json.JSONModel();
oModel.loadData('../model/rolemanagement.json');
oModel.attachRequestCompleted(oModel, function(e) {
if (e.getParameters().success) {
console.log('loading successful...');
sap.ui.getCore().setModel(oModel);
var oMTable = sap.ui.getCore().byId('mRoleTable');
oMTable.setModel(oModel);
var oRolesItemTemplate = sap.ui.getCore().byId('oRolesItemTemplateId');
oMTable.bindAggregation("items", "/roles", oRolesItemTemplate);
} else {
console.log('. . . LOADING ERROR');
console.log(e.getParameters().errorobject.statusText);
}
});
}
if i try, it only display's a table like this:
Role User
------------------------------------
Administrator [object Object]
User [object Object]
but what i need is a table like this:
Role User
------------------------------------
Administrator admin1 admin2
User user1 user2
here the same table for a better understanding:
Role User
_______________________________________________
----------------------------------------------
| ------------------------ |<---ColumnListItem
| | |<-|------FlexBox
|Administrator | --------- -------- | |
| | | admin1 || admin2 |<-|--|-------- Buttons (text: '/role/user/loginName')
| | --------- -------- | |
| ------------------------ |
----------------------------------------------
----------------------------------------------
| ------------------------ |<---ColumnListItem
| | |<-|------FlexBox
| User | --------- -------- | |
| | | user1 || user2 |<-|--|-------- Buttons (text: '/role/user/loginName')
| | --------- -------- | |
| ------------------------ |
----------------------------------------------
did someone have a solution for my problem?
The relationship between role and users within that role is one of a parent child.
This implies a list within a list. Would you not consider adopting the parent child template that deals with this scenario.
You would then select the role and then be presented with the users within that role.
Hardcoding {user/0/loginName} instead of {user} would give you the first user (but you probably knew that?)
My personal advice would be to adopt a parent child drill down (i.e. implemented through 2 views where the 2nd view is passed the role selected and it displays the users mapped to that role).
Some other minor points (from a best practice perspective) that I have picked up in my reading and coding: use jQuery.sap.log.info( instead of console.log( and...
for compatibility purposes going forward the OpenUI team are recommending naming models i.e. oMTable.setModel(oModel, "roles") . This will mean adjusting the bindings to include the named model reference {roles>....}.
(Just in case this mattered to you - refer to the API documentation for details.)
now i got a solution which works fine:
controller:
var oView = this.getView();
var oController = this;
//load data for roles
var oModel = new sap.ui.model.json.JSONModel();
oModel.loadData('../model/rolemanagement.json');
oModel.attachRequestCompleted(oModel, function(e) {
if (e.getParameters().success) {
jQuery.sap.log.info('loading roles model successful...');
sap.ui.getCore().setModel(oModel);
var oMTable = sap.ui.getCore().byId('mRoleTable');
oMTable.setModel(oModel);
} else {
jQuery.sap.log.info('. . . LOADING ERROR');
jQuery.sap.log.info(e.getParameters().errorobject.statusText);
}
});
view:
new sap.m.Table('mRoleTable',{
width: '75%',
columns: [
new sap.m.Column({width: '25%', header: new sap.m.Label({text: "Role"})}),
new sap.m.Column({ header: new sap.m.Label({text: "User"})}),
],
items: {
path: "/",
template: new sap.m.ColumnListItem({
cells: [
new sap.m.Text({ text: "{roleName}" }),
new sap.ui.layout.Grid({
content: {
path: 'users',
template: new sap.m.Button('tmpBtn',{
text: '{loginName}',
type: 'Transparent',
layoutData: new sap.ui.layout.GridData({
span: "L2 M4 S5"
})
})
}
})
]
})
}
})

Resources