Cannot establish connection - source does not exist - javascript

I have a simple section in which users can connect from one element to another element as they wish. after connection can be like this. am using jsPlumb for connections.
After connections, if the user is satisfied he/she can save it,
everything is saved correctly as I want, now when user reload the page connections eg (con_6, con_18) are not displayed.
Here is json where the data are saved.
{
"movies": [
{
"left": 237,
"top": 99,
"movieid": "51"
},
{
"left": 241,
"top": 263,
"movieid": "10"
},
{
"left": 746,
"top": 184,
"movieid": "12"
}
],
"connections": [
{
"buttonid": "0",
"movieid": "12"
},
{
"buttonid": "4",
"movieid": "12"
}
]
}
Here is my function to load my connections
$.getJSON('datasaved/settings2.json', function (data) {
var flowchartconnection =data.connections;
for( var j = 0; j < flowchartconnection.length; j++ ) {
console.log(flowchartconnection[j].buttonid);
jsPlumb.connect({ source: flowchartconnection[j].buttonid, target: flowchartconnection[j].movieid });
console.log(jsPlumb.connect);
}
});
Unfortunately, I am getting the following error:
Cannot establish a connection - source does not exist.
Here is live demo :live demo
Here is js plumb connect function documentation: js plumb connect
Here is my console.log from my live demo : live demo
As you can see on the console the source and target id is available on the DOM before the connections happen,
Can you please tell me what am I doing wrong?

Related

How to synchronize asynchronous calls to Slides api and Slides class built in App Script?

I am trying to create a slide in Google App Script and then add a text box to this newly created slide. The first call is to the Slides api and the second call is made using inbuilt methods. However, because of the asynchronous nature of these two lines, the 2nd is operating before the 1st and causing an obvious error.
Slides.Presentations.batchUpdate({'requests': requests}, presentationId);
var shape = presentation.getSlideById(newpageId).insertShape(SlidesApp.ShapeType.TEXT_BOX, 0, 0, width, height/4);
My question would be: How to create a callback or use a promise to make the needed adjustments?
I tried a different approach, I grouped all the request in chronological order and it worked:
var requests = [{
'createSlide': {
'objectId': newpageId,
'insertionIndex': current_index,
'slideLayoutReference': {
'predefinedLayout': 'BLANK'
}
}
},
{
"createShape": {
"objectId": `silaComment${questionNumber}${token}`,
"elementProperties": {
"pageObjectId": newpageId,
"size": {
"width": {
"magnitude": 3000000,
"unit": "EMU"
},
"height": {
"magnitude": 3000000,
"unit": "EMU"
}
},
"transform": {
"scaleX": 0.6807,
"scaleY": 0.4585,
"translateX": 6583050,
"translateY": 1673950,
"unit": "EMU"
}
},
"shapeType": "WAVE"
}
},
{
"insertText": {
"objectId": `silaComment${questionNumber}${token}`,
"text": comment + '\nasked by ' + name,
"insertionIndex": 0
}
}];
Slides.Presentations.batchUpdate({'requests': requests}, presentationId);
You could simply wait:
Utilities.sleep();
But this requires estimating the api call execution time.
Apps script currently doesn't support promises. Even if it did, the batchUpdate call to the api doesn't return a promise.

Error in web worker using importScripts(defiant.min.js)

I'm trying to use defiant.js in a web worker, since I'm doing heavy computation in addition to the JSON.search.
However I keep getting a
Uncaught Error: Uncaught ReferenceError: Defiant is not defined
I created a simple example using part of the defiant demo code.
Does anyone know whether this is a defiant.js issue or am I just importing the script wrong?
Or is there another solution on how this can be done?
JS in main.html
var obj = {
"car": [
{"id": 10, "color": "silver", "name": "Volvo"},
{"id": 11, "color": "red", "name": "Saab"},
{"id": 12, "color": "red", "name": "Peugeot"},
{"id": 13, "color": "yellow", "name": "Porsche"}
],
"bike": [
{"id": 20, "color": "black", "name": "Cannondale"},
{"id": 21, "color": "red", "name": "Shimano"}
]
}
var worker = new Worker('defiantWW.js');
worker.addEventListener('message', function(e) {
console.log( e.data);
}, false);
worker.postMessage(obj);
web worker file
self.addEventListener('message', function(e) {
importScripts('defiant.min.js')
var obj=e.data;
var search = JSON.search(obj, '//car[color="yellow"]/name');
self.postMessage(search);
}, false);
EDIT
changing the position of importScripts() as suggested by dandavis in comments - but same result
web worker file v2
importScripts('defiant.min.js')
self.addEventListener('message', function(e) {
var obj=e.data;
var search = JSON.search(obj, '//car[color="yellow"]/name');
self.postMessage(search);
}, false);
Sadly enough defiantJS does not support the use within a web-worker.
Got feedback from Hakan Bilgin on the issue:
There is already support for web workers in Defiant.js
<script src="defiant.min.js"></script>
<script>
var obj = {
"car": [
{"id": 10, "color": "silver", "name": "Volvo"},
{"id": 11, "color": "red", "name": "Saab"},
{"id": 12, "color": "red", "name": "Peugeot"},
{"id": 13, "color": "yellow", "name": "Porsche"}
],
"bike": [
{"id": 20, "color": "black", "name": "Cannondale"},
{"id": 21, "color": "red", "name": "Shimano"}
]
};
Defiant.getSnapshot(obj, function(snapshot) {
var found = JSON.search(snapshot, '//car');
console.log(found);
});
</script>
[Snapshot] doesn't give me access to defiant from within my own web-worker.
I can execute the Snapshot in the main thread and then post the result to my web-worker, however the large JSON (5-15mb) is handled only in the web-worker. I would have to pass it over to the main thread, run the Snapshot (which is executed in another web-worker) and then pass the result back to my WW.
Since I'm using the JSON.search quite often that would induce a lot of unnecessary overhead on the main thread.
No...you can not access Defiant from within a web worker
hi to load a service worker try this link:
https://developers.google.com/web/fundamentals/primers/service-workers
as it mentioned:
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/sw.js').then(function(registration) {
// Registration was successful
console.log('ServiceWorker registration successful with scope: ', registration.scope);
}, function(err) {
// registration failed :(
console.log('ServiceWorker registration failed: ', err);
});
});
}

Multiplication and setInterval javascript

I'm making an incremental game and I have what I want working in a JSFiddle but I can't for the life of me get it to work on my actual website. Here's what happens on my website.
Here's my code for working this out:
SetInterval(function() {
for(var outer in user.upgrades)
{
for(var inner in user.upgrades[outer])
{
loadedUser.upgrades[outer][inner].cost = Math.floor(user.upgrades[outer][inner].cost * Math.pow(user.upgrades[outer][inner].scale, loadedUser.upgrades[outer][inner].owned));
}
}
}, 10);
The loadedUser object and user object:
var costScaling = 1.15;
const user = {
"name": "",
"stats": {
"click": 1,
"level": 1,
"xp": 0,
"melons": 0,
"mps": 0,
},
"upgrades": {
"melons": {
"mash": {
"name": "Mash - 1MPS",
"cost": 50,
"value": 1,
"owned": 0,
"scale": costScaling
}
The loadedUser would be the same as this however in the upgrades.melons in the amount but there would be how many they own.
So, my issue is as you can see in the gyazo is that it turns into a really big number very quickly however on the JSFiddle is exactly what I want and I'm struggling to get it work locally, on the console is the value of user.upgrades which shouldn't even change. If you need anymore code just ask.

elasticsearch autosuggest returning tricky JSON

I'm running a node.js server that sends queries to an elasticsearch instance. Here is an example of the JSON returned by the query:
{
"took": 2,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"failed": 0
},
"hits": {
"total": 9290,
"max_score": 0,
"hits": []
},
"suggest": {
"postSuggest": [
{
"text": "a",
"offset": 0,
"length": 1,
"options": [
{
"text": "Academic Librarian",
"score": 2
},
{
"text": "Able Seamen",
"score": 1
},
{
"text": "Academic Dean",
"score": 1
},
{
"text": "Academic Deans-Registrar",
"score": 1
},
{
"text": "Accessory Designer",
"score": 1
}
]
}
]
}
}
I need to create an array containing each job title as a string. I've run into this weird behavior that I can't figure out. Whenever I try to pull values out of the JSON, I can't go below options or everything comes back as undefined.
For example:
arr.push(results.suggest.postSuggest) will push just what you'd expect: all the stuff inside postSuggest.
arr.push(results.suggest.postSuggest.options) will come up as undefined even though I can see it when I run it without .options. This is also true for anything below .options.
I think it may be because .options is some sort of built-in function that acts on variables, so instead of seeing options as JSON and is instead trying to run a function on results.suggest.postSuggest
arr.push(results.suggest.postSuggest.options)
postSuggest is an array of object.options inside postSuggest is also array of object. So first you need to get postSuggest by postSuggest[0] and then
postSuggest[0].options to get array of options
This below snippet can be usefule
var myObj = {..}
// used jquery just to demonstrate postSuggest is an Array
console.log($.isArray(myObj.suggest.postSuggest)) //return true
var getPostSuggest =myObj.suggest.postSuggest //Array of object
var getOptions = getPostSuggest[0].options; // 0 since it contain only one element
console.log(getOptions.length) ; // 5 , contain 5 objects
getOptions.forEach(function(item){
document.write("<pre>Score is "+ item.score + " Text</pre>")
})
Jsfiddle

angular $watch over a particular field for all objects of an array

I have an array of halls like this, which I am getting from a $http.get().
$scope.halls = [
{
"_id": "524886d4c6d8a5a3b8949f6f",
"alias": "",
"hallId": "2",
"locationHint": "Near support team",
"name": "Conference Hall",
"bookQueue": [],
"occupancy": {
"occupied": true,
"occupiedBy": "Vignesh",
"purpose": "Sync up",
"team": "Edge",
"timeRange": {
"from": "2013-10-02T19:08:44.752Z",
"to": "2013-10-02T19:08:44.752Z"
}
},
"capabilities": [
"ceiling mic",
"room speaker",
"projector",
"Mac machine"
]
},
{
"_id": "524886fbc6d8a5a3b8949f70",
"alias": "",
"hallId": "3",
"locationHint": "Near Edge Team",
"name": "Training room",
"bookQueue": [],
"occupancy": {
"occupied": true,
"occupiedBy": "Tharma",
"purpose": "Review",
"team": "Platform",
"timeRange": {
"from": "2013-10-02T19:08:44.752Z",
"to": "2013-10-02T19:08:44.752Z"
}
},
"capabilities": [
"ceiling mic",
"room speaker",
"projector"
]
},
{
"_id": "52488794c6d8a5a3b8949f71",
"alias": "",
"hallId": "4",
"locationHint": "Near front office",
"name": "Front Office Discussion room",
"bookQueue": [],
"occupancy": {
"occupied": false,
"occupiedBy": "",
"purpose": "",
"team": "",
"timeRange": {
"from": "2013-10-02T19:08:44.752Z",
"to": "2013-10-02T19:08:44.752Z"
}
},
"capabilities": [
"ceiling mic",
"room speaker",
"TV"
]
}
]
I want to update the hall.occupancy, when the current date ( Date.now() )is greater than hall.occupancy.timeRange.to . In this case, I am not going to watch hall.occupancy.timeRange.to because, it is not the property that is going to change. Is there an angular way to do this, because it would get really messy to put a setInterval.
I am not really sure on how to go about this.
I am still in the early stages of learning angular, so it would be good if you were gentle in pointing out an efficient way.
I don't think that is something you can easily do. the $watch function watches a certain angular expression executed in the scope. You don't have a $scope.hall so it won't do anything. You could possibly watch each instance, but what if you add or remove items from the array?
$scope.$watch('halls[0].occupancy.timeRange.to', function(a, b) {
It would probably be better to just watch the halls array and loop through it to do your check on each item when anything changes. That is basically what angular does to detect changes itself.
$scope.watch('halls', function (newValue, oldValue) {
var now = Date.now();
for (var i = 0; i < newValue.length; i++) {
// check each item
}
};
You can sort your array by hall.occupancy.timeRange.to and execute setInvertal to the nearest upcoming date. Do the same again after timer event is fired taking the next item from sorted list.
If your list changes you have to cancel active timeout and set the new one using described procedure.
In my opinion $digest phase is not enough if you want to create notifications for inactive users - they leave the site with opened tab and do something else (I do that very often with Stackoverflow).
However if there is a lot of user events (clicks, playing with ng-model etc) in your application you should watch time and check the list after each 10 seconds:
var watchFn = function() {
var d = new Date();
return '' + d.getMinutes() + Math.floor(d.getSeconds()/10);
};
$scope.$watch(watchFn, function() {
console.log('User did something and $watch is fired after minimum 10s.');
});
Perhaps, I am doing this to solve this problem, but I am not sure if this is the best way.
setInterval(function(){
if($scope.halls)
{
for(var i =0 ;i< $scope.halls.length;i++){
var hall = $scope.halls[i];
if(hall.occupancy.timeRange.to){
if(Date.now() > new Date(hall.occupancy.timeRange.to.toString())){
//change occupancy.. either dequeue from blockQueue, shift to occupancy, or change occupancy.occupied to false
$scope.halls[i].occupancy = {occupied:false,occupiedBy:"",purpose:"",team:"",timeRange:{from:"",to:""}};
socket.emit('updateHall',$scope.halls[i]);
$scope.$apply();
}
}
}
}
},500);
So, basically, it checks every 500 milliseconds whether the current time is later than hall.occupancy.timeRange.to , if so, it resets the hall.occupancy field.
Let me know if you have a better solution.

Categories

Resources