GraphQL schema with nested objects - express

How to write schema for this kind of response.
{
"adult": false,
"backdrop_path": "/dnaitaoCh8MftfYEVnprcuYExZp.jpg",
"belongs_to_collection": {
"id": 256322,
"name": "The Purge Collection",
"poster_path": "/nP3c8mTSxlis4vfg0UjlkK8LRG9.jpg",
"backdrop_path": "/quFWGOA4I5KCTsyDbvLh6PHNZwv.jpg"
},
"budget": 13000000,
"genres": [
{
"id": 28,
"name": "Action"
},
{
"id": 27,
"name": "Horror"
},
{
"id": 878,
"name": "Science Fiction"
},
{
"id": 53,
"name": "Thriller"
}
]
}

const typeDefs = `
type BelongsToCollectionType {
id: ID!
name: String
poster_path: String
backdrop_path: String
}
type GenreType {
id: ID!
name: String
}
type SomeType {
adult: Boolean
backdrop_path: String
belongs_to_collection: BelongsToCollectionType
budget: Int
genres: [GenreType]!
}
`;

Soon after I asked this question I figured it out. Here is the schema:
const MovieType = new GraphQLObjectType({
name: 'Movie',
fields: () => ({
id: { type: GraphQLString },
adult: { type: GraphQLBoolean },
backdrop_path: { type: GraphQLString },
belongs_to_collection: { type: BelongsToCollection },
budget: { type: GraphQLInt },
overview: { type: GraphQLString },
popularity: { type: GraphQLInt },
poster_path: { type: GraphQLString },
production_companies: {
type: new GraphQLList(CompaniesType)
},
genres: {
type: new GraphQLList(GenreType)
},
release_date: { type: GraphQLString },
tagline: { type: GraphQLString },
title: { type: GraphQLString },
vote_average: { type: GraphQLInt },
vote_count: { type: GraphQLInt }
})
});
const CompaniesType = new GraphQLObjectType({
name: 'ProductionCompanies',
fields: {
id: { type: GraphQLInt },
name: { type: GraphQLString },
logo_path: { type: GraphQLString },
original_country: { type: GraphQLString }
}
});
const GenreType = new GraphQLObjectType({
name: 'Genre',
fields: () => ({
id: { type: GraphQLInt },
name: { type: GraphQLString }
})
})
const BelongsToCollection = new GraphQLObjectType({
name: 'BelongsToCollection',
fields: () => ({
id: { type: GraphQLInt },
name: { type: GraphQLString },
poster_path: { type: GraphQLString },
backdrop_path: { type: GraphQLString }
})
});

Related

AJV validate string against an array of objects

I'm trying to use AJV to check that parent_IDs on child objects are valid IDs on the parent objects.
I can get it to work by validating against a single parent object like this:
const ajv = new Ajv({
$data: true,
allErrors: true,
verbose: true,
});
addFormats(ajv, ["uuid"]);
const schema = {
type: "object",
properties: {
parentObjects: {
type: "array",
items: {
type: "object",
properties: {
id: { type: "string", format: "uuid" },
name: { type: "string" },
},
required: ["id", "name"],
},
},
childObjects: {
type: "array",
items: {
type: "object",
properties: {
id: { type: "string", format: "uuid" },
name: { type: "string" },
parent_id: {
type: "string",
format: "uuid",
const: { $data: "/parentObjects/0/id" },
},
},
required: ["id", "name", "parent_id"],
},
},
},
};
const data = {
parentObjects: [
{
id: "3bc169ba-99c4-448a-8c22-5c2593ccc9ee",
name: "larry",
},
{
id: "d2e92e51-cb56-4451-bf8b-349d82fde107",
name: "curly",
},
{
id: "b99f61f5-f417-4129-9315-ab049d2b618d",
name: "moe",
},
],
childObjects: [
{
id: "bd86603f-fb1d-4075-94f5-619337d43b98",
name: "stan",
parent_id: "3bc169ba-99c4-448a-8c22-5c2593ccc9ee",
},
{
id: "c2b80273-bf2b-4898-a44b-a758a436cb37",
name: "oliver",
parent_id: "e13b7c34-6cb5-4ef4-83a7-7d11c2bd4a1f",
},
],
};
ajv.validate(schema, data);
console.log(ajv.errors);
};
But what I need is to be able to validate against all parent objects, something like:
childObjects: {
type: "array",
items: {
type: "object",
properties: {
id: { type: "string", format: "uuid" },
name: { type: "string" },
parent_id: {
type: "string",
format: "uuid",
enum: { $data: "/parentObjects/*/id" },
},
},
required: ["id", "name", "parent_id"],
},
},
I can't find a way to use a wildcard for the array index "/parentObjects/*/id" or a way to iterate through all of the parentObjects. I could map the parentObject IDs outside of AJV, create another array and validate against that, but it seems like overkill - I feel like I'm missing something simple in AJV which would allow me to do this without generating a new array.

Is there a edge weighted spring embedded layout in cytoscape.js?

We have a requirement to show nodes and edges graph in our Angular application and we chose to do it in cytoscape over high charts/amCharts/D3. Cytoscape is faster in loading and is the only library to handle 1000s of nodes that we have. Others break or lags.
We downloaded cytoscape app and were able to see a layout 'Edge weighted spring embedded'. It shows our interconnected nodes in a overall globe-like layout.
Now I want the same in cytoscape js and looks like we only have handful of layouts in https://js.cytoscape.org/
Does this layout possible in cytoscape js? How to achieve this? (Currently using fcose layout but we really like the globe look that 'Edge weighted spring embedded layout brings.
EDIT:
Here is another example: I want to achieve this layout in cytoscape.js.
What layout I should follow? Or is this something not available in js and only available in desktop App
There are three options I think:
The Compound Spring Embedder layout cose
The Compound Spring Embedder layout by Bilkent (for an enhanced compound node placement) cose-bilkent
The Constraint-Based Layout cola.js
They all use some sort of force directed layout, I think you should give them a try and use the one most fitting to your needs. There are many parameters you can set for each layout, so take a closer look at them too. For example, if you set infinite to true in the cola.js layout, you will see that you can move the nodes around and see the layout force them back to or to a fitting position:
document.addEventListener("DOMContentLoaded", function() {
var cy = (window.cy = cytoscape({
container: document.getElementById("cy"),
autounselectify: true,
boxSelectionEnabled: false,
layout: {
name: "cola",
infinite: true,
fit: false
},
style: [{
selector: "node",
css: {
"background-color": "#f92411"
}
},
{
selector: "edge",
css: {
"line-color": "#f92411"
}
}
],
elements: {
nodes: [{
data: {
id: "1",
label: "P"
}
},
{
data: {
id: "2",
label: "sucrose phosphate phosphatase"
}
},
{
data: {
id: "4",
label: "sucrose 6-phosphate"
}
},
{
data: {
id: "6",
label: "sucrose"
}
},
{
data: {
id: "8",
label: "invertase"
}
},
{
data: {
id: "10",
label: "fructose"
}
},
{
data: {
id: "12",
label: "fructokinase"
}
},
{
data: {
id: "14",
label: "fructose 6-phosphate"
}
},
{
data: {
id: "20",
label: "phosphoglucose isomerase"
}
},
{
data: {
id: "22",
label: "glucose 6-phosphate"
}
},
{
data: {
id: "28",
label: "glucose"
}
},
{
data: {
id: "30",
label: "hexokinase"
}
},
{
data: {
id: "33",
label: "sucrose synthase"
}
},
{
data: {
id: "36",
label: "UDP - glucose"
}
},
{
data: {
id: "38",
label: "sucrose phosphate synthase"
}
},
{
data: {
id: "41",
label: "UDP"
}
},
{
data: {
id: "44",
label: "fructose 6-phosphate"
}
},
{
data: {
id: "46",
label: "ATP"
}
},
{
data: {
id: "47",
label: "ATP"
}
},
{
data: {
id: "52",
label: "ATP"
}
},
{
data: {
id: "57",
label: "ADP"
}
},
{
data: {
id: "66",
label: "PP"
}
},
{
data: {
id: "71",
label: "UTP"
}
},
{
data: {
id: "76",
label: "UDP glucose pyrophosphorylase"
}
},
{
data: {
id: "80",
label: "glucose 1-phosphate"
}
},
{
data: {
id: "86",
label: "phospho- glucomutase (cPGM)"
}
},
{
data: {
id: "89",
label: "G1P transporter"
}
},
{
data: {
id: "90",
label: "P"
}
},
{
data: {
id: "95",
label: "P"
}
},
{
data: {
id: "102",
label: "P"
}
},
{
data: {
id: "103",
label: "P"
}
},
{
data: {
id: "104",
label: "G6P transporter"
}
},
{
data: {
id: "109",
label: "glucose 6-phosphate"
}
},
{
data: {
id: "115",
label: "phospho- glucomutase (cPGM)"
}
},
{
data: {
id: "121",
label: "glucose 1-phosphate"
}
},
{
data: {
id: "128",
label: "ADPglucose pyrophosphorylase (pAGPase)"
}
},
{
data: {
id: "130",
label: "ADP - glucose"
}
},
{
data: {
id: "136",
label: "PP"
}
},
{
data: {
id: "141",
label: "ATP"
}
},
{
data: {
id: "148",
label: "inorganic diphosphatase"
}
},
{
data: {
id: "149",
label: "P"
}
},
{
data: {
id: "156",
label: "phosphate transporter"
}
},
{
data: {
id: "158",
label: "P"
}
},
{
data: {
id: "164",
label: "starch synthase (simpl.)"
}
},
{
data: {
id: "166",
label: "ADP"
}
},
{
data: {
id: "172",
label: "starch"
}
},
{
data: {
id: "178",
label: "ATP/ADP transporter"
}
},
{
data: {
id: "179",
label: "ADP"
}
},
{
data: {
id: "184",
label: "ADP"
}
},
{
data: {
id: "189",
label: "ATP"
}
}
],
edges: [{
data: {
source: "2",
target: "1"
}
},
{
data: {
source: "4",
target: "2"
}
},
{
data: {
source: "2",
target: "6"
}
},
{
data: {
source: "6",
target: "8"
}
},
{
data: {
source: "8",
target: "10"
}
},
{
data: {
source: "12",
target: "14"
}
},
{
data: {
source: "14",
target: "20"
}
},
{
data: {
source: "20",
target: "22"
}
},
{
data: {
source: "8",
target: "28"
}
},
{
data: {
source: "28",
target: "30"
}
},
{
data: {
source: "30",
target: "22"
}
},
{
data: {
source: "6",
target: "33"
}
},
{
data: {
source: "33",
target: "10"
}
},
{
data: {
source: "33",
target: "36"
}
},
{
data: {
source: "36",
target: "38"
}
},
{
data: {
source: "38",
target: "4"
}
},
{
data: {
source: "38",
target: "41"
}
},
{
data: {
source: "41",
target: "33"
}
},
{
data: {
source: "44",
target: "38"
}
},
{
data: {
source: "52",
target: "12"
}
},
{
data: {
source: "12",
target: "57"
}
},
{
data: {
source: "46",
target: "30"
}
},
{
data: {
source: "30",
target: "47"
}
},
{
data: {
source: "71",
target: "76"
}
},
{
data: {
source: "76",
target: "66"
}
},
{
data: {
source: "76",
target: "36"
}
},
{
data: {
source: "80",
target: "76"
}
},
{
data: {
source: "22",
target: "86"
}
},
{
data: {
source: "86",
target: "80"
}
},
{
data: {
source: "95",
target: "89"
}
},
{
data: {
source: "89",
target: "90"
}
},
{
data: {
source: "102",
target: "104"
}
},
{
data: {
source: "80",
target: "89"
}
},
{
data: {
source: "104",
target: "109"
}
},
{
data: {
source: "115",
target: "109"
}
},
{
data: {
source: "121",
target: "89"
}
},
{
data: {
source: "121",
target: "115"
}
},
{
data: {
source: "121",
target: "128"
}
},
{
data: {
source: "128",
target: "130"
}
},
{
data: {
source: "141",
target: "128"
}
},
{
data: {
source: "128",
target: "136"
}
},
{
data: {
source: "136",
target: "148"
}
},
{
data: {
source: "148",
target: "149"
}
},
{
data: {
source: "149",
target: "156"
}
},
{
data: {
source: "156",
target: "158"
}
},
{
data: {
source: "130",
target: "164"
}
},
{
data: {
source: "164",
target: "166"
}
},
{
data: {
source: "178",
target: "179"
}
},
{
data: {
source: "184",
target: "178"
}
},
{
data: {
source: "178",
target: "189"
}
},
{
data: {
source: "141",
target: "178"
}
},
{
data: {
source: "104",
target: "103"
}
},
{
data: {
source: "10",
target: "12"
}
},
{
data: {
source: "164",
target: "172"
}
},
{
data: {
source: "22",
target: "104"
}
}
]
}
}));
cy.unbind("tapend");
cy.bind("tapend", "node", function() {
cy.animate({
fit: {
eles: cy.elements(),
padding: 20
},
center: {
eles: cy.elements()
}
}, {
duration: 500
});
});
});
body {
font-family: helvetica;
font-size: 14px;
}
#cy {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 999;
}
h1 {
opacity: 0.5;
font-size: 1em;
}
<!DOCTYPE>
<html>
<head>
<title>cytoscape-cola.js demo</title>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">
<script src="https://unpkg.com/cytoscape/dist/cytoscape.min.js"></script>
<!-- for testing with local version of cytoscape.js -->
<!--<script src="../cytoscape.js/build/cytoscape.js"></script>-->
<script src="https://unpkg.com/webcola/WebCola/cola.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cytoscape-cola#2.3.0/cytoscape-cola.min.js"></script>
</head>
<body>
<h1>cytoscape-cola demo</h1>
<div id="cy"></div>
</body>
</html>
You can try "Euler" layout, it might give the same expected layout that you wanted. It is euler.js. I am using this layout for my own data set and is giving similar layout that you have shown above.

Elastic (animated) edges in graph with nodes exerting gravitational pull on neighbours?

Is there a layout extension for Cytoscape that enables a dynamic behavior similar to that of the Neo4j Browser, i.e. when you drag a node, its edges are elastic to some extend, but that also drag connected nodes along part of the way (I'd call it localized gravity)?
Update:
The example I'm working on uses the CoSE Bilkent (compound) layout extension, but it doesn't seem to support the effect/animation I'm after out of the box. I had hoped the scarcely documented { gravity: 1 } option might be related - after all, when a node pulls other nodes along, that could well be described as gravity - but changing the setting on a small sample graph had no such effect; some digging ensued and I now think that setting has to do with how close to the graph's center nodes are displayed. I then looked at all layout demos, none seem to display the effect I'm after out of the box. AllegroViva appears to implement similar behavior (video), but from my understanding, it's rendering a time series in that video (so might just be manually redrawing the graph). Their website seems to be disfunct, too.
What I'm looking for is something easy, ideally out of the box, or something that can be implemented quickly. Unfortunately, I'm not quite sure what the right search term would be for what I want (especially in Cytoscape's domain). Hence me asking what is admittedly a very high-level question. Today, I found out Visjs calls it physics events (or at least uses the effect I'm after as part of that demo) - but as I mentioned, gravity in Cytoscape is apparently not what I'm looking for. At this point, however, I'm merely trying to establish if Cytoscape is the right library, or whether I need to look at others, like Alchemy (cf. its Philosophers' Relatedness example).
Answer:
Thank you for editing the question, I think i can help you with this one. Cytoscape.js has this feature buried deep in the extension layouts, specifically in cytoscape.js-cola. The layout is a physics layout with "springy" like nodes, so that the distance between them stays the same. The catch here is, that in the paragraph Notes, the author describes this:
If you want to maintain interactivity, you probably should not mix infinite: true with fit: true. Fitting naturally changes the zoom level, making dragging misaligned and feel weird to users --- though it still works technically. Better to just fit: false when infinite: true, and cy.center() or cy.fit() on layoutready.
The alignment option isn't as flexible as the raw Cola option. Here, only integers can be used to specify relative positioning, so it's a bit limited. If you'd like to see a more sophisticated implementation, please send a pull request.
Code:
So this example should work (note that the nodes can be moved, but they tend to stay in formation because of their already optimal position):
document.addEventListener("DOMContentLoaded", function() {
var cy = (window.cy = cytoscape({
container: document.getElementById("cy"),
autounselectify: true,
boxSelectionEnabled: false,
layout: {
name: "cola",
infinite: true,
fit: false
},
style: [{
selector: "node",
css: {
"background-color": "#f92411"
}
},
{
selector: "edge",
css: {
"line-color": "#f92411"
}
}
],
elements: {
nodes: [{
data: {
id: "1",
label: "P"
}
},
{
data: {
id: "2",
label: "sucrose phosphate phosphatase"
}
},
{
data: {
id: "4",
label: "sucrose 6-phosphate"
}
},
{
data: {
id: "6",
label: "sucrose"
}
},
{
data: {
id: "8",
label: "invertase"
}
},
{
data: {
id: "10",
label: "fructose"
}
},
{
data: {
id: "12",
label: "fructokinase"
}
},
{
data: {
id: "14",
label: "fructose 6-phosphate"
}
},
{
data: {
id: "20",
label: "phosphoglucose isomerase"
}
},
{
data: {
id: "22",
label: "glucose 6-phosphate"
}
},
{
data: {
id: "28",
label: "glucose"
}
},
{
data: {
id: "30",
label: "hexokinase"
}
},
{
data: {
id: "33",
label: "sucrose synthase"
}
},
{
data: {
id: "36",
label: "UDP - glucose"
}
},
{
data: {
id: "38",
label: "sucrose phosphate synthase"
}
},
{
data: {
id: "41",
label: "UDP"
}
},
{
data: {
id: "44",
label: "fructose 6-phosphate"
}
},
{
data: {
id: "46",
label: "ATP"
}
},
{
data: {
id: "47",
label: "ATP"
}
},
{
data: {
id: "52",
label: "ATP"
}
},
{
data: {
id: "57",
label: "ADP"
}
},
{
data: {
id: "66",
label: "PP"
}
},
{
data: {
id: "71",
label: "UTP"
}
},
{
data: {
id: "76",
label: "UDP glucose pyrophosphorylase"
}
},
{
data: {
id: "80",
label: "glucose 1-phosphate"
}
},
{
data: {
id: "86",
label: "phospho- glucomutase (cPGM)"
}
},
{
data: {
id: "89",
label: "G1P transporter"
}
},
{
data: {
id: "90",
label: "P"
}
},
{
data: {
id: "95",
label: "P"
}
},
{
data: {
id: "102",
label: "P"
}
},
{
data: {
id: "103",
label: "P"
}
},
{
data: {
id: "104",
label: "G6P transporter"
}
},
{
data: {
id: "109",
label: "glucose 6-phosphate"
}
},
{
data: {
id: "115",
label: "phospho- glucomutase (cPGM)"
}
},
{
data: {
id: "121",
label: "glucose 1-phosphate"
}
},
{
data: {
id: "128",
label: "ADPglucose pyrophosphorylase (pAGPase)"
}
},
{
data: {
id: "130",
label: "ADP - glucose"
}
},
{
data: {
id: "136",
label: "PP"
}
},
{
data: {
id: "141",
label: "ATP"
}
},
{
data: {
id: "148",
label: "inorganic diphosphatase"
}
},
{
data: {
id: "149",
label: "P"
}
},
{
data: {
id: "156",
label: "phosphate transporter"
}
},
{
data: {
id: "158",
label: "P"
}
},
{
data: {
id: "164",
label: "starch synthase (simpl.)"
}
},
{
data: {
id: "166",
label: "ADP"
}
},
{
data: {
id: "172",
label: "starch"
}
},
{
data: {
id: "178",
label: "ATP/ADP transporter"
}
},
{
data: {
id: "179",
label: "ADP"
}
},
{
data: {
id: "184",
label: "ADP"
}
},
{
data: {
id: "189",
label: "ATP"
}
}
],
edges: [{
data: {
source: "2",
target: "1"
}
},
{
data: {
source: "4",
target: "2"
}
},
{
data: {
source: "2",
target: "6"
}
},
{
data: {
source: "6",
target: "8"
}
},
{
data: {
source: "8",
target: "10"
}
},
{
data: {
source: "12",
target: "14"
}
},
{
data: {
source: "14",
target: "20"
}
},
{
data: {
source: "20",
target: "22"
}
},
{
data: {
source: "8",
target: "28"
}
},
{
data: {
source: "28",
target: "30"
}
},
{
data: {
source: "30",
target: "22"
}
},
{
data: {
source: "6",
target: "33"
}
},
{
data: {
source: "33",
target: "10"
}
},
{
data: {
source: "33",
target: "36"
}
},
{
data: {
source: "36",
target: "38"
}
},
{
data: {
source: "38",
target: "4"
}
},
{
data: {
source: "38",
target: "41"
}
},
{
data: {
source: "41",
target: "33"
}
},
{
data: {
source: "44",
target: "38"
}
},
{
data: {
source: "52",
target: "12"
}
},
{
data: {
source: "12",
target: "57"
}
},
{
data: {
source: "46",
target: "30"
}
},
{
data: {
source: "30",
target: "47"
}
},
{
data: {
source: "71",
target: "76"
}
},
{
data: {
source: "76",
target: "66"
}
},
{
data: {
source: "76",
target: "36"
}
},
{
data: {
source: "80",
target: "76"
}
},
{
data: {
source: "22",
target: "86"
}
},
{
data: {
source: "86",
target: "80"
}
},
{
data: {
source: "95",
target: "89"
}
},
{
data: {
source: "89",
target: "90"
}
},
{
data: {
source: "102",
target: "104"
}
},
{
data: {
source: "80",
target: "89"
}
},
{
data: {
source: "104",
target: "109"
}
},
{
data: {
source: "115",
target: "109"
}
},
{
data: {
source: "121",
target: "89"
}
},
{
data: {
source: "121",
target: "115"
}
},
{
data: {
source: "121",
target: "128"
}
},
{
data: {
source: "128",
target: "130"
}
},
{
data: {
source: "141",
target: "128"
}
},
{
data: {
source: "128",
target: "136"
}
},
{
data: {
source: "136",
target: "148"
}
},
{
data: {
source: "148",
target: "149"
}
},
{
data: {
source: "149",
target: "156"
}
},
{
data: {
source: "156",
target: "158"
}
},
{
data: {
source: "130",
target: "164"
}
},
{
data: {
source: "164",
target: "166"
}
},
{
data: {
source: "178",
target: "179"
}
},
{
data: {
source: "184",
target: "178"
}
},
{
data: {
source: "178",
target: "189"
}
},
{
data: {
source: "141",
target: "178"
}
},
{
data: {
source: "104",
target: "103"
}
},
{
data: {
source: "10",
target: "12"
}
},
{
data: {
source: "164",
target: "172"
}
},
{
data: {
source: "22",
target: "104"
}
}
]
}
}));
cy.unbind("tapend");
cy.bind("tapend", "node", function() {
cy.animate({
fit: {
eles: cy.elements(),
padding: 20
},
center: {
eles: cy.elements()
}
}, {
duration: 500
});
});
});
body {
font-family: helvetica;
font-size: 14px;
}
#cy {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
z-index: 999;
}
h1 {
opacity: 0.5;
font-size: 1em;
}
<!DOCTYPE>
<html>
<head>
<title>cytoscape-cola.js demo</title>
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1, maximum-scale=1">
<script src="https://unpkg.com/cytoscape/dist/cytoscape.min.js"></script>
<!-- for testing with local version of cytoscape.js -->
<!--<script src="../cytoscape.js/build/cytoscape.js"></script>-->
<script src="https://unpkg.com/webcola/WebCola/cola.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/cytoscape-cola#2.3.0/cytoscape-cola.min.js"></script>
</head>
<body>
<h1>cytoscape-cola demo</h1>
<div id="cy"></div>
</body>
</html>
Conclusion:
Cytoscape.js has the ability to display the force layout, but it is a little worse than the two examples you provided (they can display the graph without moving the nodes to their optimal position but the user preferred one). If you like to use cytoscape.js, you can do that just fine, but always consider which use cases you need and check, if any other application can handle the situation better (cytoscape.js has so many awesome features you can use, so if you can make it work, cytoscape would be my way to go).
Best of luck!
You can use force-directed layout of d3.js Here is an example graph.
I believe Neo4j Browser also uses d3.js
From the official website:
The default Neo4j Server has a powerful, customizable data visualization tool based on the built-in D3.js library.
I found a video that may be similar as your questionUse of Cytoscape.js for Client project, also there is another extension LAYOUT with d3.js cytoscape.js-d3-forcethat may be a good reference.

Complex array at QML

I got in trouble with very simple code:
property var pagesAllModels: {
ru: [
{ title: qsTr("New"), url: "http://bash.im" },
{ title: qsTr("Random"), url: "http://bash.im/random" },
{ title: qsTr("Best"), url: "http://bash.im/best" },
{ title: qsTr("By rating"), url: "http://bash.im/byrating" },
{ title: qsTr("Abyss"), url: "http://bash.im/abyss" },
{ title: qsTr("Abyss top"), url: "http://bash.im/abysstop" },
{ title: qsTr("Abyss best"), url: "http://bash.im/abyssbest" },
],
eng: [
{ title: "Latest", url: "http://bash.org/?latest" },
{ title: "Browse", url: "http://bash.org/?browse" },
{ title: "Random", url: "http://bash.org/?random" },
{ title: "Top", url: "http://bash.org/?top" }
]
}
That code in QML gives me error at line "eng: [" with error "expected lexem ," but in pure javascript everything work fine. What's wrong?
That's because your code is illegal JSON array definition. Web browsers are accepting it because they aren't strict about JS syntax, but QML engine is really strict :
In a key:value pair in associative array, the key must be a string, so it must have quotes around it, else it would be confused with a (non-existing) variable name.
property var pagesAllModels: {
"ru": [
{ "title": qsTr("New"), "url": "http://bash.im" },
{ "title": qsTr("Random"), "url": "http://bash.im/random" },
{ "title": qsTr("Best"), "url": "http://bash.im/best" },
{ "title": qsTr("By rating"), "url": "http://bash.im/byrating" },
{ "title": qsTr("Abyss"), "url": "http://bash.im/abyss" },
{ "title": qsTr("Abyss top"), "url": "http://bash.im/abysstop" },
{ "title": qsTr("Abyss best"), "url": "http://bash.im/abyssbest" }
],
"eng": [
{ "title": "Latest", "url": "http://bash.org/?latest" },
{ "title": "Browse", "url": "http://bash.org/?browse" },
{ "title": "Random", "url": "http://bash.org/?random" },
{ "title": "Top", "url": "http://bash.org/?top" }
]
}
And it works !
Try this
property var pagesAllModels: {
ru: [
{ title: qsTr("New"), url: "http://bash.im" },
{ title: qsTr("Random"), url: "http://bash.im/random" },
{ title: qsTr("Best"), url: "http://bash.im/best" },
{ title: qsTr("By rating"), url: "http://bash.im/byrating" },
{ title: qsTr("Abyss"), url: "http://bash.im/abyss" },
{ title: qsTr("Abyss top"), url: "http://bash.im/abysstop" },
{ title: qsTr("Abyss best"), url: "http://bash.im/abyssbest" }
],
eng: [
{ title: "Latest", url: "http://bash.org/?latest" },
{ title: "Browse", url: "http://bash.org/?browse" },
{ title: "Random", url: "http://bash.org/?random" },
{ title: "Top", url: "http://bash.org/?top" }
]
}
Hope this will resolve your issue
associative arrays separates by semicolon ";"
Try this
property var pagesAllModels: {
ru: [
{ title: qsTr("New"), url: "http://bash.im" },
{ title: qsTr("Random"), url: "http://bash.im/random" },
{ title: qsTr("Best"), url: "http://bash.im/best" },
{ title: qsTr("By rating"), url: "http://bash.im/byrating" },
{ title: qsTr("Abyss"), url: "http://bash.im/abyss" },
{ title: qsTr("Abyss top"), url: "http://bash.im/abysstop" },
{ title: qsTr("Abyss best"), url: "http://bash.im/abyssbest" },
];
eng: [
{ title: "Latest", url: "http://bash.org/?latest" },
{ title: "Browse", url: "http://bash.org/?browse" },
{ title: "Random", url: "http://bash.org/?random" },
{ title: "Top", url: "http://bash.org/?top" }
]
}

using Select2 with Durandal

Hi I am trying to use Select2 (multiselect) with Durandal (http://jsfiddle.net/anasnakawa/6XvqX/381/),
but the popup does not work below is part of my VM and HTML, here I am trying to bind a list of states to an input it should work as an auto complete but there seems to a issue showing the selection popup, can someone please help
define(['durandal/app', 'services/datacontext', 'plugins/router', 'services/bindinghandlers'],
function (app, datacontext, router) {
var withs = ko.observableArray(),
states = [
{ id: "AL", text: "Alabama" },
{ id: "AK", text: "Alaska" },
{ id: "AZ", text: "Arizona" },
{ id: "AR", text: "Arkansas" },
{ id: "CA", text: "California" },
{ id: "CO", text: "Colorado" },
{ id: "CT", text: "Connecticut" },
{ id: "DE", text: "Delaware" },
{ id: "FL", text: "Florida" },
{ id: "GA", text: "Georgia" },
{ id: "HI", text: "Hawaii" },
{ id: "ID", text: "Idaho" },
{ id: "IL", text: "Illinois" },
{ id: "IN", text: "Indiana" },
{ id: "IA", text: "Iowa" },
{ id: "KS", text: "Kansas" },
{ id: "KY", text: "Kentucky" },
{ id: "LA", text: "Louisiana" },
{ id: "ME", text: "Maine" },
{ id: "MD", text: "Maryland" },
{ id: "MA", text: "Massachusetts" },
{ id: "MI", text: "Michigan" },
{ id: "MN", text: "Minnesota" },
{ id: "MS", text: "Mississippi" },
{ id: "MO", text: "Missouri" },
{ id: "MT", text: "Montana" },
{ id: "NE", text: "Nebraska" },
{ id: "NV", text: "Nevada" },
{ id: "NH", text: "New Hampshire" },
{ id: "NJ", text: "New Jersey" },
{ id: "NM", text: "New Mexico" },
{ id: "NY", text: "New York" },
{ id: "NC", text: "North Carolina" },
{ id: "ND", text: "North Dakota" },
{ id: "OH", text: "Ohio" },
{ id: "OK", text: "Oklahoma" },
{ id: "OR", text: "Oregon" },
{ id: "PA", text: "Pennsylvania" },
{ id: "RI", text: "Rhode Island" },
{ id: "SC", text: "South Carolina" },
{ id: "SD", text: "South Dakota" },
{ id: "TN", text: "Tennessee" },
{ id: "TX", text: "Texas" },
{ id: "UT", text: "Utah" },
{ id: "VT", text: "Vermont" },
{ id: "VA", text: "Virginia" },
{ id: "WA", text: "Washington" },
{ id: "WV", text: "West Virginia" },
{ id: "WI", text: "Wisconsin" },
{ id: "WY", text: "Wyoming" }
];
var vm = {
withs: withs,
states: states,
};
return vm;
});
<select multiple="true" data-bind="options: states, optionsValue: 'id', optionsText: 'text', selectedOptions: withs, select2: {}" style="width: 300px"></select>
Register select2 in the Require.js configuration inside main.js:
requirejs.config({
paths: {
'select2': 'path/to/select2'
}
});
Define it in your view model:
define(['select2'], function (select2) {
// ...
});
Don't forget to declare it. You'll have to use the attached callback:
var vm = {
withs: withs,
states: states,
attached: function() {
$('select').select2();
}
};