How to get current location after moving node to save to database new loc.
myDiagram.addDigramListener("SelectionMoved",
function(e) {
let part = e.subject.part;
console.log(part)
}
)
But the part always is null, why?
I was able to use the following code to get new location and key
myDiagram.addDiagramListener("SelectionMoved", function(event) {
// https://gojs.net/latest/api/symbols/Part.html#location
// * PART
var selectedNode = event.diagram.selection.first();
console.log("selectedNode",selectedNode);
console.log("selectedNodeKey",selectedNode.key);
console.log("selectedNode", selectedNode.location.toString());
console.log("selectedNode", selectedNode.location.x);
console.log("selectedNode", selectedNode.location.y);
console.log("locationObject", selectedNode.locationObject);
//Save new location
// key: selectedNode.key
// location-x: selectedNode.location.x
// location-y: selectedNode.location.y
});
e.subject is a collection, which is the selection of all moved Parts. There may be more than one part moved.
If you are reasonably sure that there is only one Part moved, you can write:
myDiagram.addDigramListener("SelectionMoved",
function(e) {
let part = e.subject.first();
console.log(part.toString())
}
)
But if you just want to save the location to the DB, why not make a two-way data binding on Location? The flowchart example demonstrates this:
// The Node.location comes from the "loc" property of the node data,
// converted by the Point.parse static method.
// If the Node.location is changed, it updates the "loc" property of the node data,
// converting back using the Point.stringify static method.
new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
Related
i have a question about the event "upgradeneeded".
i need to check the data base every time the user reload the page, but how to fire it with out upgrade the version of the indexeddb, or it's the unique solution ?
request.addEventListener('upgradeneeded', event => {
var db = event.target.result;
var planningObjectStore = db.transaction("planningSave", "read").objectStore("planningSave");
});
"upgradeneeded" is only fired when you need to change the schema, which you signal by changing the version number. If you're not modifying the schema - e.g. you're just reading/writing to existing object stores - use the "success" event instead. Also, there's an implicit transaction within the "upgradeneeded" event, so no need to call transaction() there.
var request = indexedDB.open("mydb", 1); // version 1
// only fires for newly created databases, before "success"
request.addEventListener("upgradeneeded", event => {
var db = event.target.result;
var planningObjectStore = db.createObjectStore("planningSave");
// write initial data into the store
});
// fires after any successful open of the database
request.addEventListener("success", event => {
var db = event.target.result;
var tx = db.transaction("planningSave");
var planningObjectStore = tx.objectStore("planningSave");
// read data within the new transaction
});
I'm new to mxGraph, I want to get the vertex (cell) all related data when choosing it (clicking it), if you clicked the properties of a certain cell you will get its data, how can I get it with the code?
I tried this answer, but show this error
Update:
this code gives me an object of the clicked cell (mxGraph v3.9.8).
mxGraph.prototype.addListener(mxEvent.CLICK, function(sender, event){
var mouseEvent = event.getProperty("event");
var selectedCell = event.getProperty("cell");
console.log(selectedCell);
});
There is a function called 'showProperties' belonging to the mxEditor class. In there you can see how it works to show (and get) the properties of a cell.
Be sure the user object for these properties is a node, i.e.:
var doc = mxUtils.createXmlDocument();
var node = doc.createElement('MyNode');
node.setAttribute('label', 'My Name');
node.setAttribute('notes', 'My cell notes');
this helps me
mxGraph.prototype.addListener(mxEvent.CLICK, function(sender, event){
var mouseEvent = event.getProperty("event");
var selectedCell = event.getProperty("cell");
console.log(selectedCell);
});
As an example on basic setup one index is created.
db.onupgradeneeded = function(event) {
var db = event.target.result;
var store = db.createObjectStore('name', { keyPath: 'id' });
store.createIndex('by name', 'name', { unique: false });
};
Question:
Is it possible to create/append more indexes to the same objectStore on the future versionupdate? Since if I try:
db.onupgradeneeded = function(event) {
var db = event.target.result;
var store = db.createObjectStore('name', { keyPath: 'id' });
store.createIndex('by newName', 'newName', { unique: false });
};
It throws an error that current objectStore does already exist. An if I try to create store reference using transaction:
db.onupgradeneeded = function(event) {
var db = event.target.result;
var store = db.transaction('name', 'readwrite').objectStore('name');
store.createIndex('by newName', 'newName', { unique: false });
};
It throws that version change transaction is currently running
Yes it is possible. It can be a bit confusing at first. You want to get the existing object store via the implicit transaction created for you within onupgradeneeded. This is a transaction of type versionchange which is basically like a readwrite transaction but specific to the onupgradeneeded handler function.
Something like this:
var request = indexedDB.open(name, oldVersionPlusOne);
request.onupgradeneeded = myOnUpgradeNeeded;
function myOnUpgradeNeeded(event) {
// Get a reference to the request related to this event
// #type IDBOpenRequest (a specialized type of IDBRequest)
var request = event.target;
// Get a reference to the IDBDatabase object for this request
// #type IDBDatabase
var db = request.result;
// Get a reference to the implicit transaction for this request
// #type IDBTransaction
var txn = request.transaction;
// Now, get a reference to the existing object store
// #type IDBObjectStore
var store = txn.objectStore('myStore');
// Now, optionally inspect index names, or create a new index
console.log('existing index names in store', store.indexNames);
// Add a new index to the existing object store
store.createIndex(...);
}
You also will want to take care to increment the version so as to guarantee the onupgradeneeded handler function is called, and to represent that your schema (basically the set of tables and indices and properties of things) has changed in the new version.
You will also need to rewrite the function so that you only create or make changes based on the version. You can use event.oldVersion to help with this, or things like db.objectStoreNames.contains.
Something like this:
function myOnUpgradeNeeded(event) {
var is_new_db = isNaN(event.oldVersion) || event.oldVersion === 0;
if(is_new_db) {
var db = event.target.result;
var store = db.createObjectStore(...);
store.createIndex('my-initial-index');
// Now that you decided you want a second index, you also need
// to do this for brand new databases
store.createIndex('my-second-new-index');
}
// But if the database already exists, we are not creating things,
// instead we are modifying the existing things to get into the
// new state of things we want
var is_old_db_not_yet_current_version = !isNaN(event.oldVersion) && event.oldVersion < 2;
if(is_old_db_not_yet_current_version) {
var txn = event.target.transaction;
var store = txn.objectStore('store');
store.createIndex('my-second-new-index');
}
}
Pay close attention to the fact that I used event.target.transaction instead of db.transaction(...). These are not at all the same thing. One references an existing transaction, and one creates a new one.
Finally, and in addition, a personal rule of mine and not a formal coding requirement, you should never be using db.transaction() from within onupgradeneeded. Stick to modifying the schema when doing upgrades, and do all data changes outside of it.
I am working on a web application that allows for divs to be drag and dropped/rearranged. The new order of the divs is stored in local storage and if the page is refreshed or navigated away from and then back to, the user's chosen order is then fetched from local storage and displayed to the page. So far I have most of these things working, however when the page is refreshed/navigated away from and back to, the divs are no longer able to be moved around. In the console it appears that the event listeners are no longer on the draggable targets. How can I structure/edit my code so that the divs can be rearranged even if the user has refreshed or come back to the page at a later point in time? (I think the way I am handling events currently is also not very good, so suggestions for how to improve that are more than welcome.)
// get two groups of elements, those that are draggable and those that are drop targets
var draggable = document.querySelectorAll('[draggable]');
var targets = document.querySelectorAll('[data-drop-target]');
// div immediately surrounding bus routes
var busList = document.getElementById("bus-list");
var busListBuses = busList.children;
// make array from busListBuses which is an htmlCollection (not currently using this)
var divArr = Array.from(busListBuses);
// store the id of the draggable element when drag starts
function handleDragStart(e) {
e.dataTransfer.setData("text", this.id); // sets 'text' value to equal the id of this
this.classList.add("drag-start"); // class for styling the element being dragged
}
function handleDragEnd(e) {
e.target.classList.remove('drag-start');
}
function handleDragEnterLeave(e) {
//
}
// handles dragover event (moving your source div over the target div element)
// If drop event occurs, the function retrieves the draggable element’s id from the DataTransfer object
function handleOverDrop(e) {
e.preventDefault();
var draggedId = e.dataTransfer.getData("text"); // retrieves drag data (DOMString) for specified type
var draggedEl = document.getElementById(draggedId);
draggedEl.parentNode.insertBefore(draggedEl, this); // inserts element being dragged into list
var draggedArray = Array.from(draggedEl.parentNode.children); // creates new array which updates current location of each route
if (e.type === "drop") {
// when dropped, update localstorage
savePage(draggedArray);
}
}
// get each full bus-route div in #bus-list with p content as single arr item each
// called when item is dropped
function savePage(dArray) {
// honestly i can't remember what this does precisely
// but i can't seem to add to localstorage in the way i want without it
var arr = Array.prototype.map.call(dArray, function(elem) {
return elem.outerHTML;
});
localStorage.newList = JSON.stringify(arr); // have to stringify the array in order to add it to localstorage
}
// ideally it should just update the order of the bus routes to reflect local storage
// and add classes/ids to the divs etc. (hence using outerHTML)
function restorePage() {
// getting the item from localstorage
var getData = localStorage.getItem("newList");
// parsing it back into an array
var parsedData = JSON.parse(getData);
// string to hold contents of array so they can be display via innerHTML
var fullList = "";
if (localStorage.getItem("newList") === null) {
return; // maybe this is wrong but if there's nothing in local storage, don't do anything
} else {
for (let i = 0; i < parsedData.length; i++) {
fullList = fullList + parsedData[i];
}
busList.innerHTML = fullList;
}
}
// submit button to save changes to db
// probably better way to do this
for (let i = 0; i < draggable.length; i++) {
draggable[i].addEventListener("dragstart", handleDragStart);
draggable[i].addEventListener("dragend", handleDragEnd);
}
// drop target elements
for (let i = 0; i < targets.length; i++) {
targets[i].addEventListener("dragover", handleOverDrop);
targets[i].addEventListener("drop", handleOverDrop);
targets[i].addEventListener("dragenter", handleDragEnterLeave);
targets[i].addEventListener("dragleave", handleDragEnterLeave);
}
window.addEventListener('load', function(){
restorePage();
});
I am using React with Pug, here is the Pug file in case that's helpful.
html
head
title
link(rel='stylesheet', type='text/css', href='stylesheets/normalize.css' )
link(rel='stylesheet', type='text/css', href='stylesheets/style.css' )
body
div.container
div#bus-list
for route in routeInfo
- var routeID = route.ID
- var routePos = route.position
div(class=route.type, draggable="true", data-drop-target="true", id=`r-${routePos}`).bus-route
p #{route.route} #{route.route_name}
button(type="submit", value="submit") done!
script(src='js/styling.js')
I think problem is in the sequence of your code.
JavaScript code is bening parsed as script. So browser executes commands during script loading.
How it works:
Browser loads DOM without any items
Browser loads JS and adds listeners to the elements (which aren't loaded yet)
Brower fires onLoad() and your script loads elements from the storage.
End of the cycle.
You need to add listeners after you load the elements. Not before that.
Off topic
You do some repetitive calls.
You do
var getData = localStorage.getItem("newList");
var parsedData = JSON.parse(getData);
var fullList = "";
if (localStorage.getItem("newList") === null) {
return;
}
Instead of
var getData = localStorage.getItem("newList");
if (getData === null) {
return;
}
var parsedData = JSON.parse(getData);
var fullList = "";
It hurts readability and perfomance.
I would suggest you to read some books about C languague and Code Style. That will help you on your journey.
I am trying to implement the autocomplete with data from a database.
The data looks like
[
{"id":"1",name:"Jon"},
{"id":"2",name:"Carl"},
{"id":"3",name:"Jon"},
]
There is no example using such data even though this would be more common than selecting a string from a bunch of strings. Having the user select "Jon" doesn't mean anything unless you know the ID.
I was trying to add code to the following page and listen to an event when the user selects an item but first of all it's not documented in code and in the api what event that is and second none of the events seem to be triggered. Hopefully the event object would pass the object that was selected by the user (not the string) or the index of the selected item so I don't have to use access the private variable to get the object that was chosen.
ac1.dispose();
var DataItem = function(id,value){
this.id=id;
this.value=value;
};
DataItem.prototype.toString=function(){
return this.value;
};
DataItem.prototype.valueOf=function(){
return this.value;
};
var tcMovies = [
new DataItem(1,"one"),
new DataItem(2,"onetwo")
];
var ac1 = goog.ui.ac.createSimpleAutoComplete(
tcMovies, document.getElementById('txtInput1'), false);
goog.events.listen(ac1,goog.ui.ac.AutoComplete.EventType.SELECT,
function(e){
//never gets called
console.log(e);
//hoping to get an index so I can do something like
// ac1.getMatcher().rows_[selectedindex].id
// probably should not use rows_ but there is no get
// method for that either
}
);
Fiddling around a bit and looking through the source code I did find what hopefully is the way to implement it. The following comment in autocomplete.js would suggest it is the correct way:
/**
* Field value was updated. A row field is included and is non-null when a
* row has been selected. The value of the row typically includes fields:
* contactData and formattedValue as well as a toString function (though none
* of these fields are guaranteed to exist). The row field may be used to
* return custom-type row data.
*/
UPDATE: 'update',
Open the following page, press F12 and run the following code in the console.
//remove existing autocomplete
ac1.dispose();
//define data, need toString
// to display the values
var DataItem = function(id,value){
this.id=id;
this.value=value;
};
DataItem.prototype.toString=function(){
return this.value;
};
// create data
var tcMovies = [
new DataItem(1,"abbbbbbbb"),
new DataItem(2,"aabbbbbbb"),
new DataItem(3,"aaabbbbbb"),
new DataItem(4,"aaaabbbbb"),
new DataItem(5,"aaaaabbbb"),
new DataItem(6,"aaaaaabbb"),
];
// use easy method to create and attach the autocomplete
var ac1 = goog.ui.ac.createSimpleAutoComplete(
tcMovies, document.getElementById('txtInput1'), false);
//listen to UPDATE
goog.events.listen(ac1,goog.ui.ac.AutoComplete.EventType.UPDATE,
function(e){
//e.row should be the selected value
console.log("user selected",e.row);
}
);