MutationObserver not observing in ie11 after using its disconnect function - javascript-events

My code is as below
var originalTitle = document.title.split("#")[0];
var testtar = document.getElementsByTagName('title')[0];
try{
document.attachEvent('onpropertychange', function (evt) {
console.log('inside attachEvent');
if(evt.propertyName === 'title' && document.title !== originalTitle) {
setTimeout(function () {
document.title = originalTitle;
}, 0);
}
});
}
catch(e){
function disconnect(){
observer.disconnect();
setTimeout(function(){
observer.observe(testtar, config);
console.log(observer)
},1000);
}
var observer = new MutationObserver(function(mutations) {
testtar.innerHTML = originalTitle;
disconnect();
});
var config = { attributes: true, childList: true, characterData: true, characterDataOldValue: true };
observer.observe(testtar, config);
};
I am trying to check for title change using MutationObserver. but once i call observer.disconnect() and again call its observe() method it doesn't work.
the title changes for the second time but still testtar.innerHTML is not set to originalTitle. please help

Related

laravel set up ckeditor/ckeditor5-export-pdf

I try to set up plugin ckeditor/ckeditor5-export-pdf on my Laravel App But I cant do this. I still get issues like: Uncaught TypeError: Failed to resolve module specifier "#ckeditor/ckeditor5-export-pdf/src/exportpdf". Relative references must start with either "/", "./", or "../".
I did all steps as in docs: https://ckeditor.com/docs/ckeditor5/latest/features/export-pdf.html#configuration But when I try use import ExportPdf from '#ckeditor/ckeditor5-export-pdf/src/exportpdf'; I get the error like above. Please help. Maybe some have stuck on this issue before
import ExportPdf from '#ckeditor/ckeditor5-export-pdf/src/exportpdf';
console.log(ExportPdf);
$(document).ready(function () {
/*function ExportPdf(editor) {
editor.execute('exportPdf');
}*/
function SimpleUploadAdapter(editor) {
editor.plugins.get('FileRepository').createUploadAdapter = function(loader) {
return {
upload: function() {
return loader.file
.then(function (file) {
return new Promise(function(resolve, reject) {
// Init request
var xhr = new XMLHttpRequest();
xhr.open('POST', '/admin/instructions/ckmedia', true);
xhr.setRequestHeader('x-csrf-token', window._token);
xhr.setRequestHeader('Accept', 'application/json');
xhr.responseType = 'json';
// Init listeners
var genericErrorText = `Couldn't upload file: ${ file.name }.`;
xhr.addEventListener('error', function() { reject(genericErrorText) });
xhr.addEventListener('abort', function() { reject() });
xhr.addEventListener('load', function() {
var response = xhr.response;
if (!response || xhr.status !== 201) {
return reject(response && response.message ? `${genericErrorText}\n${xhr.status} ${response.message}` : `${genericErrorText}\n ${xhr.status} ${xhr.statusText}`);
}
$('form').append('<input type="hidden" name="ck-media[]" value="' + response.id + '">');
resolve({ default: response.url });
});
if (xhr.upload) {
xhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable) {
loader.uploadTotal = e.total;
loader.uploaded = e.loaded;
}
});
}
// Send request
var data = new FormData();
data.append('upload', file);
data.append('crud_id', {{ $instruction->id ?? 0 }});
xhr.send(data);
});
})
}
};
}
}
var allEditors = document.querySelectorAll('.ckeditor');
for (var i = 0; i < allEditors.length; ++i) {
ClassicEditor.create(
allEditors[i], {
extraPlugins: [SimpleUploadAdapter, /*ExportPdf*/],
/*toolbar: [
'exportPdf', '|',
],
exportPdf: {
stylesheets: [
'./path/to/fonts.css',
'EDITOR_STYLES',
'./path/to/style.css'
],
fileName: 'my-file.pdf',
converterOptions: {
format: 'A4',
margin_top: '20mm',
margin_bottom: '20mm',
margin_right: '12mm',
margin_left: '12mm',
page_orientation: 'portrait'
}
}*/
}
);
}
});
</script>```
I solved my problem with https://ckeditor.com/ckeditor-5/online-builder/ Builded what I want and setup it on my App

How to stop Kendo UI dropdown from sorting alphabetically

I have been given the fun job on taking on someone elses code and trying to figure it out...
I have been tearing my hair out trying to figure out how to to stop a Kendo UI dropdown from sorting alphabetically ?
<select id="ddlArtworkStatuses" onlyPreparedValues="true"
readOnlyInput="true" data-bind="idNameOptions: artworkStatuses,
comboboxSelectedValue: artworkStatusId"></select>
For some reason this sorts althabetically but I want it to keep the order in the datasource. I have double checked to make sure it is in the order I want.
It doesn't use the standard way of using Kendo UI and I can't find any examples anywhere of using it this way?
It binds the view to the model with this line at the top of the view I believe?
<!-- ko with: fabricationModel -->
The vm.fabrication file is this:
(function (app) {
app.namespace("models");
var resources = {
unableToDeleteArtworkMessage: "This artwork cannot be deleted because it is linked to one or more of the following: Movements, Shows, POs. Or it has Imported Costs, Sales or Restoration Cases.",
unableToBlankArtworkFullyMessage: "This artwork has some data that will not be blanked if you continue. This could be one or more of the following: Movements, Shows, POs, Imported Costs, Sales or Restoration Cases. Do you want to continue?",
deleteArtworkTitle: "Delete artwork",
blankArtworkTitle: "Blank Artwork",
duplicateTitle: "New artwork form is pre-populated",
duplicateMessage: "You can make changes to Fabrication form fields. Record will be created after you press save button",
saveError: 'An error occured during artwork saving. Changes were not saved.'
};
app.models.FabricationModel = function (datasource) {
var emitter = new app.events.EventEmitter(),
self = this,
duplicateArtwork = ko.observable(false);
this.isNewArtwork = ko.observable(false);
this.isActivated = ko.observable(false);
this.showCreationInformation = ko.observable(true);
this.wipeArtworkModel = new app.models.WipeArtworkDialogModel(datasource);
this.internalArtworkModel = ko.observable();
this.editCategoryModel = new app.models.EditDhCategoryModel();
// alert("data=" + this.artworkStatuses);
this.isReadOnly = ko.computed(function () {
if (!self.internalArtworkModel()) {
return true;
}
return self.internalArtworkModel().isReadOnly();
});
this.canSaveStudioStatusOnly = ko.computed(function () {
if (!self.internalArtworkModel()) {
return false;
}
return self.internalArtworkModel().isUnblockStatusActive()
&& self.internalArtworkModel().isReadOnly()
&& self.internalArtworkModel().isStudioStatusVisible();
});
this.canSaveCatRaisOnly = ko.computed(function () {
if (!self.internalArtworkModel()) {
return false;
}
return self.internalArtworkModel().isReadOnly()
&& self.internalArtworkModel().isArchiveProvenanceWriter();
});
this.isNewOrDuplicating = ko.computed(function () {
return self.isNewArtwork() || duplicateArtwork();
});
this.activate = function (params) {
var id = params.id || 0;
self.isNewArtwork(!id);
return self.loadArtworkDetails(id);
};
this.isValid = function () {
return self.internalArtworkModel() && self.internalArtworkModel().errors().length == 0;
};
this.loadArtworkDetails = function (id) {
var action = self.isNewArtwork() ? datasource.artworks.getEmpty : datasource.artworks.getById;
return action(id)
.done(function (result) {
var mapper = app.mappers["fabrication"],
model = mapper.map(result.data);
self.internalArtworkModel(model);
self.editCategoryModel.categoryId(model.defaultDhCategoryId);
self.editCategoryModel.setModeAsCategoryChanging();
if (self.isNewArtwork()) {
self.editCategoryModel.setModeAsCreation();
self.editCategoryModel.show();
}
self.isActivated(true);
duplicateArtwork(false);
$("a#science-link").attr("href", window.location.href);
triggerLoadEvent();
});
};
this.saveArtwork = function () {
if (self.isValid()) {
return saveInternal($.noop);
}
};
this.editCategory = function () {
self.editCategoryModel.show();
};
this.onLoad = function (callback) {
emitter.subscribe("load", callback);
};
this.onCategoryChanged = function (callback) {
emitter.subscribe("category-changed", callback);
};
this.onDelete = function (callback) {
emitter.subscribe("delete", callback);
};
this.onCreated = function (callback) {
emitter.subscribe("artwork-created", callback);
};
this.onUpdated = function (callback) {
emitter.subscribe("artwork-updated", callback);
};
this.onBlanked = function (callback) {
emitter.subscribe("blanked", callback);
};
this.saveStudioStatusInt = function () {
return saveStudioStatusInternal($.noop);
};
this.saveCatRaisInt = function () {
return saveCatRaisInternal($.noop);
};
this.saveStudioStatus = ko.asyncCommand({
execute: function (complete) {
saveStudioStatusInternal(complete);
},
canExecute: function (isExecuting) {
return !isExecuting && self.canSaveStudioStatusOnly();
}
});
this.saveCatRais = ko.asyncCommand({
execute: function (complete) {
saveCatRaisInternal(complete);
},
canExecute: function (isExecuting) {
return !isExecuting && self.canSaveCatRaisOnly();
}
});
this.save = ko.asyncCommand({
execute: function (complete) {
return saveInternal(complete);
},
canExecute: function (isExecuting) {
if (!self.isValid()) {
showErrors();
}
return !isExecuting && self.isValid();
}
});
function saveStudioStatusInternal(completeCallback) {
var model = self.internalArtworkModel();
triggerSaveStudioStatusEvent();
datasource.artworks.saveStudioStatus(model.artworkId(), model.artworkStatusId(), model.studioStatusId).always(completeCallback);
}
function saveCatRaisInternal(completeCallback) {
var model = self.internalArtworkModel();
triggerSaveStudioStatusEvent();
datasource.artworks.saveCatRais(model.artworkId(), model.inclusion(), model.image(), model.details(), model.crReady(), model.selectedVolume.selected.value).always(completeCallback);
}
this.onSaveStudioStatus = function (callback) {
emitter.subscribe("saveStudioStatus", callback);
};
function triggerSaveStudioStatusEvent() {
emitter.publish("saveStudioStatus");
}
this.beginArtworkDeletion = function () {
if (!self.internalArtworkModel().canBeBlanked) {
jAlert(resources.unableToDeleteArtworkMessage, resources.deleteArtworkTitle);
return;
}
self.wipeArtworkModel.beginArtworkDeletion(self.internalArtworkModel().artworkId());
};
this.beginArtworkBlanking = function () {
if (!self.internalArtworkModel().canBeBlanked) {
//jAlert(resources.unableToBlankArtworkMessage, resources.blankArtworkTitle);
app.alerts.appConfirm(resources.unableToBlankArtworkFullyMessage, resources.blankArtworkTitle, function (ok) {
if (ok) {
self.wipeArtworkModel.beginArtworkBlanking(self.internalArtworkModel().artworkId());
}
});
return;
}
self.wipeArtworkModel.beginArtworkBlanking(self.internalArtworkModel().artworkId());
};
this.duplicateArtwork = function () {
if (!self.internalArtworkModel()) {
return;
}
duplicateArtwork(true);
resetModelBeforeDuplication();
if (self.isValid()) {
showErrors();
}
jAlert(resources.duplicateMessage, resources.duplicateTitle);
};
function saveInternal(completeCallback) {
var mapper = app.mappers["fabrication"];
//alert("saving now...");
var unmappedModel = mapper.toJS(self.internalArtworkModel());
if (duplicateArtwork()) {
return saveDuplicatedArtwork(unmappedModel, completeCallback);
}
if (unmappedModel.artworkId) {
return updateArtwork(unmappedModel, completeCallback);
}
return createArtwork(unmappedModel, completeCallback);
}
function saveDuplicatedArtwork(model, completeCallback) {
return datasource.artworks.duplicate(model)
.always(completeCallback)
.fail(function (response) {
jAlert(resources.saveError);
})
.done(function (id) {
triggerArtworkCreatedEvent(id);
duplicateArtwork(false);
self.showCreationInformation(true);
});
}
function updateArtwork(model, completeCallback) {
return datasource.artworks.save(model)
.always(completeCallback)
.fail(function (response) {
jAlert(resources.saveError);
})
.done(function (result) {
if (!result) {
return;
}
var mapper = app.mappers["fabrication"],
mappedModel = mapper.map(result.data);
triggerUpdateEvent(
{
dhCategory: mappedModel.dhCategory(),
refNumber: mappedModel.refNumber(),
computedTitle: mappedModel.computedTitle()
});
self.internalArtworkModel(mappedModel);
});
}
function createArtwork(model, completeCallback) {
return datasource.artworks.save(model)
.always(completeCallback)
.fail(function (response) {
jAlert(resources.saveError);
})
.done(function (id) {
if (id) {
triggerArtworkCreatedEvent(id);
}
});
}
function triggerLoadEvent() {
var model = self.internalArtworkModel();
emitter.publish("load", {
artworkId: model.artworkId() || 0,
dhCategory: model.dhCategory() || "",
refNumber: model.refNumber() || "",
computedTitle: model.computedTitle() || "",
isForSale: model.isForSale
});
}
function triggerArtworkCreatedEvent(artworkId) {
emitter.publish("artwork-created", artworkId);
}
function triggerCategoryChangedEvent() {
emitter.publish("category-changed", {
name: self.internalArtworkModel().dhCategoryName(),
id: self.internalArtworkModel().dhCategoryId()
});
}
function triggerDeleteEvent(e, artworkId) {
emitter.publish("delete", artworkId);
}
function triggerUpdateEvent(data) {
var model = self.internalArtworkModel();
data.isCategoryChanged = model.initialCategoryId !== model.dhCategoryId();
emitter.publish("artwork-updated", data);
}
function showErrors() {
var model = self.internalArtworkModel();
if (model) {
model.errors.showAllMessages();
}
}
function resetModelBeforeDuplication() {
var model = self.internalArtworkModel();
model.refNumber("");
model.computedTitle("");
model.isOnDisplay(false);
model.isOnRestoration(false);
model.salesStatus("Not set");
model.creationDate("");
model.creatorName("");
model.isFramed(false);
model.framedDate("");
model.framedUserName("");
model.framedUserInitials("");
model.framedUserId(null);
model.locations(null);
model.isInsuranceComponent(false);
model.dateWebsiteWork("");
model.dateWebsiteReady("");
model.dateWebsiteUploaded("");
model.dateRemovedFromWebsite("");
model.collectionListing("");
model.salesStatusChangedDate("");
model.salesStatusChangerUserInitials("");
model.salesStatusChangerUserName("");
self.showCreationInformation(false);
}
function triggerBlanked(artworkId) {
emitter.publish("blanked", { artworkId: artworkId, flag: true });
}
(function () {
self.editCategoryModel.onChanged(function (e, categoryId) {
self.internalArtworkModel().dhCategoryId(categoryId);
triggerCategoryChangedEvent();
});
self.editCategoryModel.onCancel(function () {
if (self.isNewArtwork()) {
self.isNewArtwork(false);
app.router.back();
}
});
self.wipeArtworkModel.onDelete(triggerDeleteEvent);
self.wipeArtworkModel.onBlank(function (e, artworkId) {
self.loadArtworkDetails(artworkId);
triggerBlanked(artworkId);
});
})();
};
})(app);
It also uses a mapper:
(function (app, ko) {
app.namespace("mappers");
var s = app.urls.shared,
datasource = app.datasource;
var mapSettings = {
selectedMedium: {
create: function (options) {
return new ListModel({
isRemoteSource: true,
url: s.get('dictionaryUrl'),
listType: datasource.dictionaryTypes.get("medium"),
currentValue: options.data,
nobutton: true,
templateName: "textAreaTemplate"
});
}
},
artist: {
create: function (options) {
return new ListModel({
isRemoteSource: true,
url: s.get('dictionaryUrl'),
listType: datasource.dictionaryTypes.get("artist"),
currentValue: options.data,
onlyPreparedValues: false
});
}
},
manager: {
create: function (options) {
return new ListModel({
isRemoteSource: true,
url: s.get('dictionaryUrl'),
listType: datasource.dictionaryTypes.get("manager"),
currentValue: options.data,
onlyPreparedValues: false
});
}
},
managerStatus: {
create: function (options) {
return new ListModel({
isRemoteSource: true,
url: s.get('dictionaryUrl'),
listType: datasource.dictionaryTypes.get("managerStatus"),
currentValue: options.data,
onlyPreparedValues: false
});
}
},
selectedVolume: {
create: function (options) {
return new ListModel({
isRemoteSource: true,
url: s.get('dictionaryUrl'),
listType: datasource.dictionaryTypes.get("volume"),
currentValue: options.data,
onlyPreparedValues: false,
readonly: !options.parent.isArchiveProvenanceWriter(),
editable: options.parent.isArchiveProvenanceWriter()
});
}
},
salesStatus: {
create: function (options) {
var value = options.data || "Not set";
return ko.observable(value);
}
},
oldReferences: {
create: function (options) {
return ko.observable(options.data);
}
},
copy: ['defaultDhCategoryId', "canBeDeleted", "canBeBlanked", "isForSale"],
ignore: ["dimensions", "dimensionUnits", "selectedMediumTypes", "selectedSeries", "selectedSubSeries", "selectedAkaNames", "selectedWebSiteMediumTypes", 'selectedWebSiteCategoryIds', "locations", "hasInTransitLocations"]
},
unmapSettings = {
ignore: ["selectedMedium", "artist", "manager", "managerStatus", "mediumTypesModel", "dimensionModel", "seriesModel", "subSeriesModel", "akaModel", "webSiteMediumTypesModel", "webSiteCategoriesModel", "selectedVolume"]
},
map = function (json) {
var convertedObject = ko.utils.parseJson(json);
var model = ko.mapping.fromJS(convertedObject, mapSettings);
model.artworkStatusesModel = new ListModel({
isRemoteSource: false,
currentValue: convertedObject.selectedArtworkStatus,
data: convertedObject.artworkStatuses,
//data: filteredSalesStatuses,
onlyPreparedValues: true,
allowNull: false,
readonly: true
});
alert("mooo=" + model.artworkStatuses()[0].name());
alert("mooo=" + model.artworkStatuses()[1].name());
alert("mooo=" + model.artworkStatuses()[2].name());
//alert("mooo=" + model.artworkStatuses()[3].name());
//alert("mooo=" + model.artworkStatuses()[4].name());
model.dhCategoryName = ko.computed(function () {
var categories = model.dhCategories();
for (var i = 0; i < categories.length; i++) {
var category = categories[i];
if (category.id() == model.dhCategoryId()) {
return category.name();
}
}
return "";
});
model.initialCategoryId = convertedObject.dhCategoryId;
model.dimensionModel = new app.models.DimensionModel(convertedObject.dimensions);
ko.utils.arrayForEach(convertedObject.dimensionUnits, function (unit) {
model.dimensionModel.units.push(unit);
});
model.locations = ko.observable(convertedObject.locations ? {
archivedLocations: $.map(convertedObject.locations, function (elem) {
return elem.isArchived ? elem : null;
}),
activeLocations: $.map(convertedObject.locations, function (elem) {
return elem.isArchived ? null : elem;
}),
hasInTransitLocations: convertedObject.hasInTransitLocations
} : convertedObject.locations);
model.mediumTypesModel = new app.models.MultilistModel(convertedObject.selectedMediumTypes, { url: s.get("mediumTypesUrl") });
model.seriesModel = new app.models.MultilistModel(convertedObject.selectedSeries, { url: s.get("seriesUrl") });
model.subSeriesModel = new app.models.MultilistModel(convertedObject.selectedSubSeries, { url: s.get("subSeriesUrl") });
model.akaModel = new app.models.MultilistModel(convertedObject.selectedAkaNames, { url: s.get("akaUrl") });
model.webSiteMediumTypesModel = new app.models.MultilistModel(convertedObject.selectedWebSiteMediumTypes, { url: s.get("webSiteMediumTypeUrl") });
model.webSiteCategoriesModel = new app.models.MultilistModel(convertedObject.selectedWebSiteCategories, { url: s.get("webSiteCategoryUrl") });
model.isStudioStatusVisible = ko.computed(function () {
var foundStatuses = ko.utils.arrayFilter(model.artworkStatuses(), function (status) {
return status.id() == model.artworkStatusId();
});
var currentStatus = foundStatuses[0];
if (currentStatus) {
return currentStatus.name().toLowerCase() == "in progress";
}
return false;
});
addValidationOptions(model);
return model;
},
toJS = function (artwork) {
var result = ko.mapping.toJS(artwork, unmapSettings);
result.artist = artwork.artist.toJS();
result.manager = artwork.manager.toJS();
result.managerStatus = artwork.managerStatus.toJS();
result.selectedMedium = artwork.selectedMedium.toJS();
result.selectedVolume = artwork.selectedVolume.toJS();
result.dimensions = artwork.dimensionModel.toJS();
result.selectedMediumTypes = artwork.mediumTypesModel.toJS();
result.selectedSeries = artwork.seriesModel.toJS();
result.selectedSubSeries = artwork.subSeriesModel.toJS();
result.selectedAkaNames = artwork.akaModel.toJS();
result.selectedWebSiteMediumTypes = artwork.webSiteMediumTypesModel.toJS();
result.selectedWebSiteCategories = artwork.webSiteCategoriesModel.toJS();
return result;
};
function isValidationRequired(model) {
var artworkStatus = ko.utils.unwrapObservable(model.artworkStatusId);
var dhCategory = ko.utils.unwrapObservable(model.dhCategoryId);
return artworkStatus == app.global.dictionary.get("compiteArtworkStatus")
&& dhCategory != app.global.dictionary.get("ignoreDHCatigory");
}
function addValidationOptions(model) {
model.artworkStatusId.extend({ required: true });
model.title.extend({ required: true });
model.artist.selected.value.extend({ required: true });
model.startYear.extend({
lessEqualThan: {
params: model.endYear,
onlyIf: function () {
return (model.endYear() != undefined && model.endYear() != null);
},
message: 'From Date should be less or equal than a To Date'
}
});
model.endYear.extend({
required: {
params: true,
onlyIf: function () {
return isValidationRequired(model);
},
message: "To Date field is required"
}
});
model.selectedMedium.selected.value.extend({
required: {
params: true,
onlyIf: function () {
return isValidationRequired(model);
},
message: "Medium is required"
}
});
model.mediumTypesModel.hasValue.extend({
equal: {
params: true,
onlyIf: function () {
return isValidationRequired(model);
},
message: "Medium Type is required"
}
});
model.akaModel.hasValue.extend({
equal: {
params: true,
onlyIf: function () {
return isValidationRequired(model);
},
message: "Aka is required"
}
});
model.isInsuranceComponent.extend({
equal: {
params: true,
onlyIf: function () {
return isValidationRequired(model);
},
message: "At least 1 Insurance component should be chosen"
}
});
model.dimensionModel.hasDimensions.extend({
equal: {
params: true,
onlyIf: function () {
return isValidationRequired(model);
},
message: "The Dimension fields should be filled"
}
});
model.errors = ko.validation.group(model, { deep: true });
}
app.mappers.fabrication = {
settings: mapSettings,
map: map,
toJS: toJS
};
})(app, ko);
Where I have the alerts, the items are in the right order, so somewhere they are getting sorted but cant find out where?!
I hope someone can help?
It would be really appreciated.
Many thanks,
David.

Execute validation with button

I'm looking to execute the Handsontable validation on the click of a button instead of on cell change. Something like this: validateCells() (return bool isValid). This function doesn't seem to be working for me.
var
data = [],
container = document.getElementById('hot-Handsontable'),
save = document.getElementById('save'),
hidden = document.getElementById('hot-Handsontable-value'),
hot,
hotIsValid = true,
emailValidator;
emptyValidator = function(value, callback) {
callback(false);
};
hot = Handsontable(container, {
data: data,
minRows: 1,
minCols: 21,
maxCols: 21,
minSpareRows: 1,
stretchH: 'all',
colHeaders: ['Test'],
columns: [{data:'Test',allowInvalid:true, validator: emptyValidator}]
});
// exclude empty rows from validation
$('.title-block .united-alert a[href^=#Handsontable]').click(function() {
var href = $(this).attr('href');
var row = href.getIdIndex();
var prop = /([^__]*)$/.exec(href)[0];
hot.selectCellByProp(parseInt(row), prop);
return false;
});
// Save event
Handsontable.Dom.addEvent(save, 'click', function(e) {
var test = hot.validateCells(); // test is undefined
if (hotIsValid === true) {
hidden.value = JSON.stringify(hot.getData());
} else {
e.preventDefault();
}
});
What you should be doing, instead of var test = hot.validateCells() is the following:
// Save event
Handsontable.Dom.addEvent(save, 'click', function(e) {
hot.validateCells(function(hotIsValid) {
if (hotIsValid === true) {
hidden.value = JSON.stringify(hot.getData());
} else {
e.preventDefault();
}
})
});
Notice that validateCells takes a callback and returns undefined. This is why you see test as undefined. One other thing to note is that the callback is executed for every cell in your table so be careful with it.

AngularJS - Strange behaviour of promises in connection with notify()

As I want to implement a chat in AngularJS, I want to use the promise/deferred principle. My ChatService looks like the following:
factory('ChatService', ['$q', '$resource', function($q, $resource) {
var Service = {};
var connected = false;
var connection;
var chatResource = $resource('/guitars/chat/:action', {action: '#action'}, {
requestChatroomId: {
params: {
action: 'requestChatroomId'
},
method: 'GET'
},
sendMessage: {
params: {
action: 'sendMessage'
},
method: 'POST'
}
});
Service.connect = function(cb) {
var deferred = $q.defer();
chatResource.requestChatroomId(function(data) {
connection = new WebSocket('ws://127.0.0.1:8888/realtime/' + data.chatroomId);
connection.onerror = function (error) {
deferred.reject('Error: ' + error);
};
connection.onmessage = function (e) {
cb.call(this, e.data);
deferred.notify(e.data);
};
connected = true;
});
return deferred.promise;
};
Service.sendMessage = function(msg) {
if(!connected) {
return;
}
chatResource.sendMessage({message: msg});
}
return Service;
}])
My controller using the ChatService is:
app.controller('ChatCtrl', ['$scope', 'ChatService', function($scope, ChatService) {
$scope.chat = {};
$scope.chat.conversation = [];
var $messages = ChatService.connect(function(message) {
$scope.$apply(function() {
// #1 THIS FIRES EVERY TIME
$scope.chat.conversation.push(message);
});
});
$messages.then(function(message) {
console.log('Finishes - should never occur!')
}, function(error) {
console.log('An error occurred!')
}, function(message) {
// #2 THIS FIRES ONLY IF THERE IS AN INTERACTION WITH THE ANGULAR MODEL
console.log(message);
});
$scope.sendMessage = function(event) {
ChatService.sendMessage($scope.chat.message);
$scope.chat.message = '';
};
}]);
If something is pushed from the server, callback #1 is called, but callback #2 wont be called until there is some interaction with the angular-model, i.e. start writing something in the input-Box. What is the reason for that behaviour?
Okay the reason was, that AngularJS was not aware of a change. So I injected the $rootScope to my ChatService:
factory('ChatService', ['$q', '$resource', '$rootScope', function($q, $resource, $rootScope) {
and in connection.onmessage I called $apply() on $rootScope:
connection.onmessage = function (e) {
deferred.notify(e.data);
$rootScope.$apply();
};

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