How can I get the siblings of a newly inserted inline? - slate.js

The following code doesn't work and I see the first inserted entity only when the code is running the second time:
editor.insertInline({
key: 'XX',
data: {},
nodes: List([
Text.create({
'Hello World!',
})
]),
type: 'deletion',
})
const insertedDeletion = value.document.getInlinesByType('deletion').first()
Immediately after inserting the inline, insertedDeletion is null. Where exactly should I check for the existence of the inline? Is there a callback?

After further investigating, I found that I need to get the value directly from the editor instance:
const insertedDeletion = editor.value.document.getInlinesByType('deletion').first()

Related

Why does the map method for the List class in flutter not work anymore?

I opened my project one day and multiple files had errors were there were none before. All of the errors were due to the map method for the list class.
The error says: "The method 'map' isn't defined for the type 'List'."
If there is no way of getting the map method to work, how should I work around this issue?
Code Snippet:
// User list from snapshot
List<TestUser> _userListFromSnapshot(QuerySnapshot snapshot) {
return snapshot.docs.map((doc){
return TestUser(
name: doc.data()['name'] ?? '',
year: doc.data()['year'] ?? 0,
school: doc.data()['school'] ?? 'School',
);
}).toList();
}
Try to add object type
return snapshot.docs.map<TestUser>((doc){

Apollo duplicates first result to every node in array of edges

I am working on a react app with react-apollo
calling data through graphql when I check in browser network tab response it shows all elements of the array different
but what I get or console.log() in my app then all elements of array same as the first element.
I don't know how to fix please help
The reason this happens is because the items in your array get "normalized" to the same values in the Apollo cache. AKA, they look the same to Apollo. This usually happens because they share the same Symbol(id).
If you print out your Apollo response object, you'll notice that each of the objects have Symbol(id) which is used by Apollo cache. Your array items probably have the same Symbol(id) which causes them to repeat. Why does this happen?
By default, Apollo cache runs this function for normalization.
export function defaultDataIdFromObject(result: any): string | null {
if (result.__typename) {
if (result.id !== undefined) {
return `${result.__typename}:${result.id}`;
}
if (result._id !== undefined) {
return `${result.__typename}:${result._id}`;
}
}
return null;
}
Your array item properties cause multiple items to return the same data id. In my case, multiple items had _id = null which caused all of these items to be repeated. When this function returns null the docs say
InMemoryCache will fall back to the path to the object in the query,
such as ROOT_QUERY.allPeople.0 for the first record returned on the
allPeople root query.
This is the behavior we actually want when our array items don't work well with defaultDataIdFromObject.
Therefore the solution is to manually configure these unique identifiers with the dataIdFromObject option passed to the InMemoryCache constructor within your ApolloClient. The following worked for me as all my objects use _id and had __typename.
const client = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache({
dataIdFromObject: o => (o._id ? `${o.__typename}:${o._id}`: null),
})
});
Put this in your App.js
cache: new InMemoryCache({
dataIdFromObject: o => o.id ? `${o.__typename}-${o.id}` : `${o.__typename}-${o.cursor}`,
})
I believe the approach in other two answers should be avoided in favor of following approach:
Actually it is quite simple. To understand how it works simply log obj as follows:
dataIdFromObject: (obj) => {
let id = defaultDataIdFromObject(obj);
console.log('defaultDataIdFromObject OBJ ID', obj, id);
}
You will see that id will be null in your logs if you have this problem.
Pay attention to logged 'obj'. It will be printed for every object returned.
These objects are the ones from which Apollo tries to get unique id ( you have to tell to Apollo which field in your object is unique for each object in your array of 'items' returned from GraphQL - the same way you pass unique value for 'key' in React when you use 'map' or other iterations when rendering DOM elements).
From Apollo dox:
By default, InMemoryCache will attempt to use the commonly found
primary keys of id and _id for the unique identifier if they exist
along with __typename on an object.
So look at logged 'obj' used by 'defaultDataIdFromObject ' - if you don't see 'id' or '_id' then you should provide the field in your object that is unique for each object.
I changed example from Apollo dox to cover three cases when you may have provided incorrect identifiers - it is for cases when you have more than one GraphQL types:
dataIdFromObject: (obj) => {
let id = defaultDataIdFromObject(obj);
console.log('defaultDataIdFromObject OBJ ID', obj, id);
if (!id) {
const { __typename: typename } = obj;
switch (typename) {
case 'Blog': {
// if you are using other than 'id' and '_id' - 'blogId' in this case
const undef = `${typename}:${obj.id}`;
const defined = `${typename}:${obj.blogId}`;
console.log('in Blogs -', undef, defined);
return `${typename}:${obj.blogId}`; // return 'blogId' as it is a unique
//identifier. Using any other identifier will lead to above defined problem.
}
case 'Post': {
// if you are using hash key and sort key then hash key is not unique.
// If you do query in DB it will always be the same.
// If you do scan in DB quite often it will be the same value.
// So use both hash key and sort key instead to avoid the problem.
// Using both ensures ID used by Apollo is always unique.
// If for post you are using hashKey of blogID and sortKey of postId
const notUniq = `${typename}:${obj.blogId}`;
const notUniq2 = `${typename}:${obj.postId}`;
const uniq = `${typename}:${obj.blogId}${obj.postId}`;
console.log('in Post -', notUniq, notUniq2, uniq);
return `${typename}:${obj.blogId}${obj.postId}`;
}
case 'Comment': {
// lets assume 'comment's identifier is 'id'
// but you dont use it in your app and do not fetch from GraphQl, that is
// you omitted 'id' in your GraphQL query definition.
const undefnd = `${typename}:${obj.id}`;
console.log('in Comment -', undefnd);
// log result - null
// to fix it simply add 'id' in your GraphQL definition.
return `${typename}:${obj.id}`;
}
default: {
console.log('one falling to default-not good-define this in separate Case', ${typename});
return id;
}
I hope now you see that the approach in other two answers are risky.
YOU ALWAYS HAVE UNIQUE IDENTIFIER. SIMPLY HELP APOLLO BY LETTING KNOW WHICH FIELD IN OBJECT IT IS. If it is not fetched by adding in query definition add it.
An alternative option to the accepted is to instead of dataIdFromObject, which appears to be for everything in the query, I was able to provide a keyFields function per type that required it.
const client = new ApolloClient({
cache: new InMemoryCache({
typePolicies: {
ItemType: {
keyFields: (obj) =>
obj.id + "-" + obj.language.id,
},
},
}),
});
In the above example ItemType can be whichever Type is specified in your schema. I happened to be joining a non-unique ID with a language to make a unique key but you can do it however you wish.

Add element to List that is inside a Map (ImmutableJS)

This is a example of what my state looks like:
state = {
messages: [
{name: 'Bruce', content: 'Hello'},
{name: 'Clark', content: 'World'}
]
}
I am writing a reducer that will take the ADD_MESSAGE action and add a message to the message list. I would like to take into account the case where the 'messages' key is not defined. I am just starting to use ImmutableJS.
This is how I wrote my function:
// This is really bad
const addMessage = (state, message) => {
let mutableState = state.toJS();
if(mutableState.messages){
mutableState.messages.push(message);
}else{
mutableState = {messages: [message]}
}
return fromJS(mutableState);
}
I'm pretty sure there is a better way to do that. It should work whether my state argument is Immutable or not. Any idea? Thank you!
This is a possible implementation:
const addMessage = (state, message) =>
state.update('messages', Immutable.List(),
msgs => msgs.push(Immutable.Map(message)));
The 2nd arg passed to update is the default value if the key doesn't exist, and the 3rd argument is a closure to take the current value for the key (or default value) and perform the required update. The code also converts the message into an Immutable.Map, but you might prefer to use an Immutable.Record type.
See https://facebook.github.io/immutable-js/docs/#/Map/update for more info on update. updateIn is also very useful for updating store state, as are set, merge, setIn and mergeIn.

How to check the type of a field before checking the value in rethinkdb?

I have few tables in rethinkdb with very varied datasets. Mostly because over time, out of simple string properties complex objects were created to be more expressive.
When I run a query, I'm making sure that all fields exist, with the hasFields - function. But what if I want to run a RegExp query on my Message property, which can be of type string or object. Of course if it is an object, I don't care about the row, but instead of ignoring it, rethinkdb throws the error:
Unhandled rejection RqlRuntimeError: Expected type STRING but found OBJECT in...
Can I somehow use typeOf to first determine the type, before running the query?
Or what would be a good way to do this?
Your question is not 100% clear to me so I'm going to restate the problem to make sure my solution gets sense.
Problem
Get all documents where the message property is of type object or the message property is a string and matches a particular regular expression (using the match method).
Solution
You basically need an if statement. For that, you can use the r.branch to 'branch' your conditions depending on these things.
Here's a very long, but clear example on how to do this:
Let's say you have these documents and you want all documents where the message property is an object or a string that has the substring 'string'. The documents look like this:
{
"id": "a1a17705-e7b0-4c84-b9d5-8a51f4599eeb" ,
"message": "invalid"
}, {
"id": "efa3e26f-2083-4066-93ac-227697476f75" ,
"message": "this is a string"
}, {
"id": "80f55c96-1960-4c38-9810-a76aef60d678" ,
"not_messages": "hello"
}, {
"id": "d59d4e9b-f1dd-4d23-a3ef-f984c2361226" ,
"message": {
"exists": true ,
"text": "this is a string"
}
}
For that , you can use the following query:
r.table('messages')
.hasFields('message') // only get document with the `message` property
.filter(function (row) {
return r.branch( // Check if it's an object
row('message').typeOf().eq('OBJECT'), // return true if it's an object
true,
r.branch( // Check if it's a string
row('message').typeOf().eq('STRING'),
r.branch( // Only return true if the `message` property ...
row('message').match('string'), // has the substring `string`
true,
false // return `false` if it's a string but doesn't match our regex
),
false // return `false` if it's neither a string or an object
)
)
})
Again this query is long and could be written a lot more elegantly, but it explains the use of branch very clearly.
A shorter way of writing this query is this:
r.table('messages')
.hasFields('message')
.filter(function (row) {
return
row('message').typeOf().eq('OBJECT')
.or(
row('message').typeOf().eq('STRING').and(row('message').match('string'))
)
})
This basically uses the and and or methods instead of branch.
This query will return you all registers on table message that have the field message and the field is String.
Cheers.
r.db('test').table('message').hasFields('message')
.filter(function (row) {
return row('message').typeOf().eq('STRING')
})

How to Populate koGrid Groups Array

I have a koGrid configured as follows:
var myItemsGrid = {
data: myItems,
columnDefs: [
{ field: 'item.title', displayName: 'Title', cellTemplate: $("#cdfUrlCellTemplate").html() },
{ field: 'item.dueTimeUtc', displayName: 'Due', cellFormatter: formatDate, sortFn: sortDates },
{ field: 'id', displayName: 'Edit', cellTemplate: $("#editCellTemplate").html() }
],
showGroupPanel: true,
groups: ['item.title'],
showFilter: false,
canSelectRows: false
};
My problem is that the groups array, which I have tried to populate using the field name of one of the fields in my grid, causes the following error:
TypeError: Cannot read property 'isAggCol' of undefined
How should I be populating the groups array so that I can set up initial grouping for my grid?
I had the same problem and took a different approach by sending an event to the grid control to group by the first heading. Something like this:
jQuery("#symbolPickerView").find(".kgGroupIcon").first().click();
This works until there is some sort of patch generally available.
I ended up having to patch the koGrid script to get the initial grouping of columns to work.
If anyone else has the problem I'm happy to provide the patched script. I will look at making a pull request to get the fix into the koGrid repository after putting it through its paces a bit more.