Change options only if something changed via AJAX Response - ajax

I need your help concerning AJAX Responses with Symfony. On my page I have select options and want only refresh them, if anything in DB has changed. Now I'm loading every five seconds and checking if data count is different. But on the other hand users could also edit/rename old options. If I only check the count it's not possible to refresh the list. So how can I check if old response different than the new one?
Thanks in advance!!
(My code in JS as follows)
let Routing = require('../../vendor/friendsofsymfony/jsrouting-bundle/Resources/public/js/router')
let Routes = require('./js_routes')
Routing.setRoutingData(Routes)
let select_options = document.getElementById("person_names")
document.addEventListener('DOMContentLoaded', function (event) {
if(window.location.href.indexOf("entity=Person&action=new") > -1 || window.location.href.indexOf("entity=Person&action=edit") > -1){
let firstRequest = true;
let responseOld
window.setInterval(function () {
new Promise( function (resolve, reject) {
let url = Routing.generate('getNewPersonList')
let xhr = new XMLHttpRequest()
xhr.open('GET', url)
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest')
xhr.addEventListener('load', function (event) {
if (this.status === 200 && this.statusText === "OK"){
resolve(JSON.parse(this.responseText))
} else {
reject(JSON.parse(this.responseText))
}
})
xhr.send()
})
.then((response) => {
debugger;
if (firstRequest){
responseOld = response
firstRequest = false
// document.cookie = "Names=" + response + "; expires=Thu, 18 Dec 2019 12:00:00 UTC; path=/refreshNames";
console.log("first")
}
if (select_options.length !== response.length) {
console.log(select_options)
console.log(response)
// Drop old options
select_options.length = 0
// Fill it with new names
for (let index = 0; index < response.length; index++) {
let $option_element = document.createElement('option')
$option_element.value = response[index].id
$option_element.text = response[index].name
select_options.appendChild($option_element)
}
}
})
.catch((error) => {
console.log(error)
})
}, 5000)
}
})

Related

response from await browser.tabs.sendMessage is set in chrome, but not in firefox

I have successfully used await browser.tabs.sendMessage in chrome to get response from the listener, but the same code in firefox does not work. await browser.tabs.sendMessage return immediately and sets response to undefined. In content script inject.js, sendResponse should be called after 1000ms timeout.
I attached a minimalistic example. Any idea why await browser.tabs.sendMessage
returns what sendResponse set only in chrome, but not in firefox?
//inject.js
(async () => {
if (typeof browser === "undefined") {
var browser = chrome;
}
browser.runtime.onMessage.addListener((msg, sender, sendResponse) => {
console.log(msg);
setTimeout(function(){
let pageObject = {a:1};
sendResponse(pageObject);
},1000)
return true;
});
})();
//background.js
(async () => {
if (typeof browser === "undefined") {
var browser = chrome;
}
//**code for injecting content scripts on extension reload**
browser.runtime.onInstalled.addListener(async () => {
let manifest = browser.runtime.getManifest();
for (const cs of manifest.content_scripts) {
for (const tab of await browser.tabs.query({ url: cs.matches })) {
browser.scripting.executeScript({
target: { tabId: tab.id },
files: cs.js,
});
}
}
});
async function SendMessageToFront(message) {
let resolve;
const promise = new Promise(r => resolve = r);
browser.tabs.query({}, async function (tabs) {
for (let index = 0; index < tabs.length; index++) {
const tab = tabs[index];
if (tab.url) {
let url = new URL(tab.url)
if (url.hostname.includes("tragetdomain.com")) {
var startTime = performance.now()
let response = await browser.tabs.sendMessage(tab.id, { message: message });
var endTime = performance.now()
console.log(`Call to doSomething took ${endTime - startTime} milliseconds`) // this takes 0ms
console.log("got response");
console.log(response); // this is undefined
console.log(browser.runtime.lastError); // this is empty
resolve(response);
break;
}
}
}
});
return promise;
}
await SendMessageToFront();
})();
I guess for the tests in firefox you do the reload of the background script (F5 or the specific button in devtools)
Just as you have coded the background you have little hope of getting an answer because every time you reload the background you break the wire with all content scripts injected into the page(s).
Move the browser check inside the "SendMessageToFront" function. Move the "SendMessageToFront" function (async is not needed) to the main thread and run that function in the main thread.
/*async*/ function SendMessageToFront(message) {
if (typeof browser === "undefined")
var browser = chrome;
let resolve;
const promise = new Promise(r => resolve = r);
browser.tabs.query({}, async function(tabs) {
for (let index = 0; index < tabs.length; index++) {
const tab = tabs[index];
if (tab.url) {
let url = new URL(tab.url);
if (url.hostname.includes("tragetdomain.com")) {
var startTime = performance.now()
let response = await browser.tabs.sendMessage(tab.id, {'message': message});
var endTime = performance.now()
console.log(`Call to doSomething took ${endTime - startTime} milliseconds`) // this takes 0ms
console.log("got response");
console.log(response); // this is undefined
console.log(browser.runtime.lastError); // this is empty
resolve(response);
break
}
}
}
});
return promise
}
(async _ => {
await SendMessageToFront()
})();
in this way you will get an error message as soon as the background is ready which tells you that the content script on the other side does not exists or it's not ready yet, but now, when the content script will be ready, you should just re-launch the function from the background script devtools
(async _ => {
await SendMessageToFront()
})();
this time you will get the correct answer {a: 1}

Chromecast Reciever App Error : '[goog.net.WebSocket] The WebSocket disconnected unexpectedly: undefined '

While creating a receiver application in chromecast we are getting a problem as :
[goog.net.WebSocket] The WebSocket disconnected unexpectedly: undefined
cast_receiver_framework.js:507 WebSocket connection to 'ws://localhost:8008/v2/ipc' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
Our receiver has simple code as in example provided by CAF receiver in chromecast documentation:
const context = cast.framework.CastReceiverContext.getInstance();
const playerManager = context.getPlayerManager();
const playbackConfig = new cast.framework.PlaybackConfig();
// Customize the license url for playback
playbackConfig.licenseUrl = 'https://wv-keyos.licensekeyserver.com/';
playbackConfig.protectionSystem = cast.framework.ContentProtection.WIDEVINE;
playbackConfig.licenseRequestHandler = requestInfo => {
requestInfo.withCredentials = true;
requestInfo.headers = {
'customdata': '<customdata>'
};
};
context.getPlayerManager().setMediaPlaybackInfoHandler((loadRequest, playbackConfig) => {
if (loadRequest.media.customData && loadRequest.media.customData.licenseUrl) {
playbackConfig.licenseUrl = loadRequest.media.customData.licenseUrl;
}
return playbackConfig;
});
function makeRequest (method, url) {
return new Promise(function (resolve, reject) {
var xhr = new XMLHttpRequest();
xhr.open(method, url);
xhr.onload = function () {
if (this.status >= 200 && this.status < 300) {
resolve(JSON.parse(xhr.response));
} else {
reject({
status: this.status,
statusText: xhr.statusText
});
}
};
xhr.onerror = function () {
reject({
status: this.status,
statusText: xhr.statusText
});
};
xhr.send();
});
}
playerManager.setMessageInterceptor(
cast.framework.messages.MessageType.LOAD,
request => {
castDebugLogger.info('MyAPP.LOG', 'Intercepting LOAD request');
if (request.media && request.media.entity) {
request.media.contentId = request.media.entity;
}
return new Promise((resolve, reject) => {
if(request.media.contentType == 'video/mp4') {
return resolve(request);
}
// Fetch content repository by requested contentId
makeRequest('GET', 'https://tse-summit.firebaseio.com/content.json?orderBy=%22$key%22&equalTo=%22'+ request.media.contentId + '%22')
.then(function (data) {
var item = data[request.media.contentId];
if(!item) {
// Content could not be found in repository
castDebugLogger.error('MyAPP.LOG', 'Content not found');
reject();
} else {
// Adjusting request to make requested content playable
request.media.contentId = item.stream.hls;
request.media.contentType = 'application/x-mpegurl';
castDebugLogger.warn('MyAPP.LOG', 'Playable URL:', request.media.contentId);
// Add metadata
var metadata = new cast.framework.messages.MovieMediaMetadata();
metadata.metadataType = cast.framework.messages.MetadataType.MOVIE;
metadata.title = item.title;
metadata.subtitle = item.author;
request.media.metadata = metadata;
resolve(request);
}
});
});
});
/** Debug Logger **/
const castDebugLogger = cast.debug.CastDebugLogger.getInstance();
// Enable debug logger and show a warning on receiver
// NOTE: make sure it is disabled on production
castDebugLogger.setEnabled(false);
playerManager.addEventListener(
cast.framework.events.category.CORE,
event => {
castDebugLogger.info('ANALYTICS', 'CORE EVENT:', event);
});
// Set verbosity level for custom tags
castDebugLogger.loggerLevelByTags = {
'MyAPP.LOG': cast.framework.LoggerLevel.WARNING,
'ANALYTICS': cast.framework.LoggerLevel.INFO,
};
/** Optimizing for smart displays **/
const playerData = new cast.framework.ui.PlayerData();
const playerDataBinder = new cast.framework.ui.PlayerDataBinder(playerData);
const touchControls = cast.framework.ui.Controls.getInstance();
let browseItems = getBrwoseItems();
function getBrwoseItems() {
let data = '"video": { \
<Encrypted Video>
}, \
"title": "Big Buck Bunny" \
}';
let browseItems = [];
for (let key in data) {
let item = new cast.framework.ui.BrowseItem();
item.entity = key;
item.title = data[key].title;
item.subtitle = data[key].description;
item.image = new cast.framework.messages.Image(data[key].poster);
item.imageType = cast.framework.ui.BrowseImageType.MOVIE;
browseItems.push(item);
}
return browseItems;
}
let browseContent = new cast.framework.ui.BrowseContent();
browseContent.title = 'Up Next';
browseContent.items = browseItems;
browseContent.targetAspectRatio =
cast.framework.ui.BrowseImageAspectRatio.LANDSCAPE_16_TO_9;
playerDataBinder.addEventListener(
cast.framework.ui.PlayerDataEventType.MEDIA_CHANGED,
(e) => {
if (!e.value) return;
// Clear default buttons and re-assign
touchControls.clearDefaultSlotAssignments();
touchControls.assignButton(
cast.framework.ui.ControlsSlot.SLOT_1,
cast.framework.ui.ControlsButton.SEEK_BACKWARD_30
);
// Media browse
touchControls.setBrowseContent(browseContent);
});
context.start({playbackConfig: playbackConfig});
This code takes the input from sender but even if sender has application ID it shows the same message.

Why do I get this error (failed) net::ERR_CONNECTION_CLOSED after ajax request?

In my localhost it works fine, but on hosting I get this error
(failed) net::ERR_CONNECTION_CLOSED.
What does this error mean and how can I solve this problem? This is a Laravel/vue project.
Code of ajax request:
var firstHalf = this.menu.slice(0, 21);
var secondHalf = this.menu.slice(21);
var result = [firstHalf,secondHalf];
this.isLoading = true;
for (let i = 0; i < result.length; i++) {
let statusCode = 200;
axios({
method: "post",
url: "/admin/menu/addMenu/",
header: {
"X-CSRF-TOKEN": $('meta[name="csrf-token"]').attr("content")
},
params: {
menu: result[i],
startDate: this.selectedDate,
order: i + 1
}
}).then(response => {
console.log("ajax")
console.log(response.status);
console.log(response);
if (i+1>= result.length) {
this.message = response.data.message;
this.modalShow = true;
this.isLoading = false;
return;
}
});
}
What I did is the following:
var verifyIdentity = formData.get('verify_identity')
if(verifyIdentity && verifyIdentity.size === 0){
formData.delete('verify_identity')
}
Basically saying, if there is a file type attribute, but it is not filled out (meaning you never actually picked the file to submit), just remove it from form data.
It's a tad different example as I don't see what you're actually submitting, but I noticed the issue on my part was due to the type="file" input fields.

How to know if all uploads completed within a loop?

I have a code that works well for sending multiple files via ajax with FormData and XMLHttpRequest;
for (var i=0, j=this.files.length; i<j; i++) {
file = this.files[i];
var formdata = new FormData();
formdata.append("images[]", file);
var xhr = new XMLHttpRequest(),
upload = xhr.upload,
id = Math.floor((Math.random() * 100000));
upload.addEventListener("loadstart", function(e){
showUploadedItem(file, this.id);
});
upload.id = id;
upload.onprogress = function(e) {
var done = e.position || e.loaded, total = e.totalSize || e.total;
)
};
upload.onload = function(e) {
if (this.status == 200) {
console.log('');
}
};
xhr.onreadystatechange = function(e) {
if ( 4 == this.readyState ) {
console.log('');
}
};
xhr.open('post', '<?php echo Yii::app()->createUrl('url') ?>', true);
xhr.send(formdata);
}
I am sending each file as a new XMLHttpRequest object inside the loop, so I do not know when I'm getting all requests ending.
Can anyone help?
Take a look at the documentation for XMLHttpRequest.
There are a couple of options that I can think of. You could use the "loadend" callback for each of them and increment a variable outside of the loop and check for the total amount of requests that were sent in each one. Once the count reaches the total number of requests, you could perform any logic or call a function that would want to call.
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest?redirectlocale=en-US&redirectslug=DOM%2FXMLHttpRequest%2FUsing_XMLHttpRequest
Otherwise, setting the async parameter to false would work as well, but then you take a performance hit waiting for each one to finish before starting the others.
Based on your answer, my solution;
var x = 0;
var lenght = this.files.length;
for (var i=0, j=lenght; i<j; i++) {
// code here
var xhr = new XMLHttpRequest(),
// code here
xhr.onreadystatechange = function(e) {
if ( 4 == this.readyState && this.status == 200 ) {
x++;
if(x == lenght) {
window.setTimeout( function(){
alert('finish');
}, 1000 );
}
}
};
// code here
}
Though it is a trivial function, it works.

Backbone collection fetch error with no information

I have a strange problem with the fetch of a backbone collection I am working with. In one particular instance of my code I perform a fetch (exactly how I do it in other areas of the code which all work fine), the fetch never seems to make it to the server and the developer tools shows the request as red with the word (canceled) in the status/text field.
I've walked this through into the backbone sync method and I see the $.ajax being built and everything looks fine. Has anyone run into this problem?
here is my code if it helps, this is a function that calls two .ashx services to first check for a file's existence then to open it. The part that isn't working for me is the "me.collection.fetch().
openDocument: function () {
var me = this,
fileId = me.model.get('id'),
userId = Dashboard.Data.Models.UserModel.get("UserInfo").User_ID,
fileRequest = '/genericHandlers/DownloadFile.ashx?id=' + fileId + '&userId=' + userId,
fileCheck = '/genericHandlers/CheckFileExistance.ashx?id=' + fileId + '&userId=' + userId;
//hide tooltip
me.hideButtonTooltips();
// Check for file existance
$.ajax({
url: fileCheck
})
.done(function (data) {
if (data && data === "true") {
document.location.href = fileRequest;
me.collection.fetch();
} else if (!!data && data === "false") {
"This file is no longer available.".notify('error');
}
})
.fail(function (data) {
"Something went wrong during the File Existance check".notify('error');
"Something went wrong during the File Existance check".log(userId, 'error', 'Docs');
});
},
my collection:
// docsCollection.js - The collection of ALL the documents available to a given user
// Document Collection
Dashboard.Collections.DocsCollection = Backbone.Collection.extend({
model: Dashboard.Models.DocumentUploadModel,
url: function () {
return 'apps/docs/Docs/' + this.userId;
},
initialize: function (options) {
this.userId = options.userId;
this.deferredFetch = this.fetch();
},
comparator: function (model) {
return -(new Date(model.get('expirationDate')));
},
getDaysSinceViewedDocuments: function () {
return this.filter(function (model) {
return model.get('daysSinceViewed') !== null;
});
},
getNewDocuments: function () {
return this.filter(function (model) {
return model.get('isNew');
});
},
getExpiredDocuments: function () {
return this.filter(function (model) {
return model.get('isExpired');
});
}
});
and my model:
Dashboard.Models.DocumentUploadModel = Backbone.Model.extend({
defaults: {
fileArray: [],
name: '',
description: '',
accesses: [],
tags: [],
expirationDate: ''
},
initialize: function () {
this.set({
userId: Dashboard.Data.Models.UserModel.get("UserInfo").User_ID,
expirationDate: (this.isNew()) ? buildExpirationDate() : this.get('expirationDate')
}, { silent: true });
function buildExpirationDate() {
var date = new Date((new Date()).getTime() + 24 * 60 * 60 * 1000 * 7),
dateString = "{0}/{1}/{2}".format(date.getMonth() + 1, date.getDate(), date.getFullYear());
return dateString;
}
},
firstFile: function () {
return this.get('fileArray')[0];
},
validate: function (attributes) {
var errors = [];
if (attributes.name === '' || attributes.name.length === 0)
errors.push({
input: 'input.txtName',
message: "You must enter a name."
});
if (attributes.description === '' || attributes.description.length === 0)
errors.push({
input: 'textarea.taDescription',
message: "You must enter a description."
});
if (errors.length > 0)
return errors;
return;
},
sync: function (method, model, options) {
var formData = new FormData(),
files = model.get("fileArray"),
$progress = $('progress'),
success = options.success,
error = options.error;
// Nothing other than create or update right now
if (method !== "create" && method !== "update")
return;
// Build formData object
formData.append("name", model.get("name"));
formData.append("description", model.get("description"));
formData.append("accesses", model.get("accesses"));
formData.append("tags", model.get("tags"));
formData.append("expirationDate", model.get("expirationDate"));
formData.append("userId", model.get("userId"));
formData.append("isNew", model.isNew());
// if not new then capture id
if (!model.isNew())
formData.append('id', model.id);
for (var i = 0; i < files.length; i++) {
formData.append('file', files[i]);
}
xhr = new XMLHttpRequest();
xhr.open('POST', '/genericHandlers/UploadDocsFile.ashx');
xhr.onload = function () {
if (xhr.status === 200) {
if (success)
success();
} else {
if (error)
error();
}
}
if ($progress.length > 0) {
xhr.upload.onprogress = function (evt) {
var complete;
if (evt.lengthComputable) {
// Do the division but if you cant put 0
complete = (evt.loaded / evt.total * 100 | 0);
$progress[0].value = $progress[0].innerHTML = complete;
}
}
}
xhr.send(formData);
},
upload: function (changedAttrs, options) {
this.save("create", changedAttrs, options);
}
});
You're assigning a value to document.location.href before you try to fetch your collection:
document.location.href = fileRequest;
me.collection.fetch();
Changing document.location.href will change the whole page and in the process, any currently running JavaScript will get shutdown so I wouldn't expect your me.collection.fetch() to ever get executed.

Resources