I'm using angular.js with C# web service and I need to increment ng-repeat item by item to show to the user as the data is updated, to do this I'm trying to use $http.get within loop for refresh data in each item. But its not working
for (var i = 0; i < conditions.length; i++) {
var configFullAsset = {
params: {
Field: Field,
SAM_ConnectionString: SAM_ConnectionString,
TreeElemId: conditions[i][0],
ConditionDate: conditions[i][1]
}
};
$http.get('application.asmx/getExtFullAssetHealth', configFullAsset)
.success(function (responseExt) {
console.log("Element: ", i);
if (i == 0)
{
$scope.showData = responseExt;
$scope.fullAssetTable_loading = false;
$scope.fullAssetTable_loaded = true;
}
else
$scope.showData = $scope.showData.concat(responseExt);
//console.log("Data item: ", $scope.showData[i].Tag);
$scope.fullData = $scope.showData;
$scope.filterData(customFilter);
})
.catch(function (err) {
console.log("Error get object: ", err);
})
.finally(function () {
// Hide loading spinner whether our call succeeded or failed.
//$scope.loading = false;
$scope.fullData = $scope.showData;
$scope.filterData(customFilter);
$scope.fullAssetTable_loading = false;
$scope.fullAssetTable_loaded = true;
console.log($scope.fullData);
});
}
The main problem into your code is the fallowing: you use i as index in the success method but is not what you expected because the loop is over until your first success will be called.
You can build the requests like this in the first phase, is much easier to read:
function buildRequests() {
return conditions.map(function(condition) {
var configFullAsset = {
params: {
Field: Field,
SAM_ConnectionString: SAM_ConnectionString,
TreeElemId: condition[0],
ConditionDate: condition[1]
}
};
return $http.get('application.asmx/getExtFullAssetHealth', configFullAsset);
});
}
Than you can handle all the requests like this:
function handleRequests() {
var requests = buildRequests();
$q.all(requests)
.then(handleRequests)
.catch(function(error) {
console.log(error);
})
.finally(function() {
$scope.fullData = $scope.showData;
$scope.filterData(customFilter);
$scope.fullAssetTable_loading = false;
$scope.fullAssetTable_loaded = true;
});
}
Than to iterate over each result to make the changes:
function handleResults(results) {
results.forEach(function(response, i) {
console.log("Element: ", i);
if (i == 0)
{
$scope.showData = response;
$scope.fullAssetTable_loading = false;
$scope.fullAssetTable_loaded = true;
}
else
$scope.showData = $scope.showData.concat(response);
//console.log("Data item: ", $scope.showData[i].Tag);
$scope.fullData = $scope.showData;
$scope.filterData(customFilter);
});
}
Do not forget to inject $q as dependency injection.
Related
I was having trouble while converting a synchronous function to asynchronous.
the existing code is like below
$scope.getTask = function (input, id) {
var result = '';
if (condition) {
// Get all tasks.
var tasks = $scope.getAllTasks(id);
if (!angular.isUndefined(tasks)) {
var result = 'Failed';
for (var i = 0; i < tasks.length; i++) {
if (condition) {
result = 'Success';
break;
}
}
}
}
else if (condition) {
result = 'Failed';
}
else {
if (input != null || input != '') {
result = input.toLowerCase();
}
}
return result;
}
$scope.getAllTasks = function (id) {
var xhr = new XMLHttpRequest();
var url = "/api/workflow/" + id;
xhr.open("GET", url, false);
xhr.send();
return JSON.parse(xhr.responseText);
}
But now i need to make this async , so i have tried using promises but that didnt help.
It is not resolving properly. Please find what i have tried
$scope.getStatus = function (input, id) {
return new Promise((resolve, reject) => {
var result = '';
if(condition){
getAllTasks(id).then(function(response){
var tasks = response.data;
if (!angular.isUndefined(tasks)) {
var status = 'Failed';
for (var i = 0; i < tasks.length; i++) {
if (condition) {
result = 'Success';
break;
}
}
}
resolve(result);
return result;
});
resolve(result);
}
else if (condition) {
result = 'Failed';
}
else {
if (input != null || input != '') {
result = input.toLowerCase();
}
}
resolve(result);
return result;
});
}
var getAllTasks = function (id) {
const url = "/api/workflow/" + id;
return $http({method: 'GET', url})
.then((response) => {
return resolve(response)
});
}
But this is always returning [object promise].
I need to return the value as string like ' Failed' 'Success'.
Suggest what i am missing here.
I know promise will return a promise object from docs, but how to handle this.
$scope.getStatus is used in directives to fill the columns in jquesry datatable.
Code snippet is below
'sTitle': "<strong>" + $translate("list.StatusColumn") + "</strong>",
'mData': function (data, type, val) {
return $scope.getStatus(data.input, data.id);
},
'width': "16%",
'defaultContent': ""
Do this:
first,Dont handle your http request here if you are handling it in your other promise:
var getAllTasks = function (id) {
const url = "/api/workflow/" + id;
return $http({method: 'GET', url});
}
second: stop returning anything from this promise's callback function as you are returning result that you are also setting in resolve and you can get it in success handler of then function like this:
$scope.getStatus = function (input, id) {
var result = '';
if(condition){
getAllTasks(id).then(function(response){
var tasks = response.data;
if (!angular.isUndefined(tasks)) {
result = 'Failed';
for (var i = 0; i < tasks.length; i++) {
if (condition) {
result = 'Success';
break;
}
}
}
return result;
});
return result;
}
else if (condition) {
result = 'Failed';
}
else {
if (input != null || input != '') {
result = input.toLowerCase();
}
}
return result;
}
console.log($scope.getStatus());
I am getting some data from the database by using angular $http. I can successfully get the data but before I can show that data to the user on the front end I want to loop through the data and make some changes.
$http.get("/getList").then(function(data ̶,̶ ̶s̶t̶a̶t̶u̶s̶ ) {
// setting data to the front end
$scope.returnedData = data.data;
},function errorCallback(response) {
console.log(response.data.message)
});
}
My Loop function:
if($scope.returnedData.modules.length > 0){
for(var i=0; i<=$scope.returnedData.modules.length; i++){
if($scope.returnedData.modules[i].carType === 2){
$scope.returnedData.modules[i].carModel = $scope.returnedData.modules[i].carModel / 52;
} else if($scope.returnedData.modules[i].truckType === 2){
$scope.returnedData.modules[i].truckModel = $scope.returnedData.modules[i].truckModel / 52;
}
}
}
How can I chain Angular promises so once I get the data I can loop through it and make changes as I want and after that set it to the front-end.
Just handle the fetched data before storing the result to $scope variable:
$http.get("/getList")
.then(function(data, status) {
if(data.data.modules.length > 0) {
for(var i=0; i<=data.data.modules.length; i++) {
if(data.data.modules[i].carType === 2) {
data.data.modules[i].carModel = data.data.modules[i].carModel / 52;
} else if(data.data.modules[i].truckType === 2){
data.data.modules[i].truckModel = data.data.modules[i].truckModel / 52;
}
}
}
// Storing the result
$scope.returnedData = data.data;
})
.catch(function(error) {
console.error(error)
});
And the similar code with check for existence and modulesWithCartypeEqualToTwo and modulesWithTrucktypeEqualToTwo arrays for more comfortable debugging:
$http.get("/getList")
.then(function(data, status) {
var modulesWithCartypeEqualToTwo = [];
var modulesWithTrucktypeEqualToTwo = [];
if(data.data.modules) {
if(data.data.modules.length > 0) {
for(var i=0; i<=data.data.modules.length; i++) {
if(data.data.modules[i].carType === 2) {
modulesWithCartypeEqualToTwo.push(data.data.modules[i])
data.data.modules[i].carModel = data.data.modules[i].carModel / 52;
} else if(data.data.modules[i].truckType === 2) {
modulesWithTrucktypeEqualToTwo.push(data.data.modules[i])
data.data.modules[i].truckModel = data.data.modules[i].truckModel / 52;
}
}
}
}
console.log('modules with carType === 2');
console.log(modulesWithCartypeEqualToTwo);
console.log('modules with truckType === 2');
console.log(modulesWithTrucktypeEqualToTwo);
// Storing the result
$scope.returnedData = data.data;
})
.catch(function(error) {
console.error(error)
});
To chain from a promise, return data to the .then method handler function:
var promise = $http.get("/getList").then(function(response ̶,̶ ̶s̶t̶a̶t̶u̶s̶ ) {
// setting data to the front end
$scope.returnedData = response.data;
͟r͟e͟t͟u͟r͟n͟ response.data;
},function errorCallback(response) {
console.log(response.data.message)
//IMPORTANT
throw response;
});
Then chain from the returned promise:
promise.then(function(data) {
if(data.modules.length > 0){
for(var i=0; i<=data.modules.length; i++){
//code ...
};
};
});
It is important to use a throw statement in the rejection handler. Otherwise the promise will be converted from a rejected promise to a fulfilled promise.
I am trying to pass an object that I build piece by piece with promises using firebase. I don't really need the object to be passed along the promise chain if there is a better way to construct the object step by step. Here is my code:
var queue = new Queue(productUpdateQueue, function(data, progress, resolve, reject) {
var incomingUpdateData = data;
var receiptID = incomingUpdateData.receiptID;
var userID = incomingUpdateData.userID;
var oldProductID = incomingUpdateData.oldProductID;
var newProductID = incomingUpdateData.newProductID;
var newReceipt = incomingUpdateData.newReceipt;
var postID = "";
var updateObject = {};
updateObject['usersPrivate/'+userID+'/receipts/'+receiptID+'/items/'+oldProductID] = null;
updateObject['usersPrivate/'+userID+'/receipts/'+receiptID+'/items/'+newProductID] = newReceipt;
clicks.child('VigLink').orderByChild('item').equalTo(oldProductID).once('value', function(cuidSnapshot) {
return cuidSnapshot.forEach(function(cuidSnapshot) {
var cuid = cuidSnapshot.key;
updateObject['clicks/VigLink/'+cuid+'/item'] = newProductID;
console.log('one');
progress(20);
});
}).then(function() {
return userReceiptMetrics.child(userID).child('receipts').child(receiptID).child('items').child(oldProductID).once('value', function(oldSnapshot) {
var data = oldSnapshot.val()
updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/items/'+oldProductID] = null
updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/items/'+newProductID] = data
if (data != null) {
updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/itemIDs/'+newProductID] = now
updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/itemIDs/'+oldProductID] = null
};
console.log('two');
progress(40);
});
}).then(function() {
return userReceiptMetrics.child(userID).child('shops').child(oldProductID).once('value', function(oldSnapshot) {
var data = oldSnapshot.val()
updateObject['userReceiptMetrics/'+userID+'/shops/'+oldProductID] = null;
updateObject['userReceiptMetrics/'+userID+'/shops/'+newProductID] = data;
if (data != null) {
updateObject['userReceiptMetrics/'+userID+'/shopIDs/'+newProductID] = now;
updateObject['userReceiptMetrics/'+userID+'/shopIDs/'+oldProductID] = null;
};
console.log('three');
progress(60);
});
}).then(function() {
return posts.once('value', function(postSnapshot) {
// use Promise.all and Array#map to wait for all these queries to finish
var allPosts = postSnapshot.val()
var postKeys = Object.keys(allPosts)
return Promise.all(postKeys.map(function(postKey) {
var postID = postKey;
return posts.child(postID).child('items').child(oldProductID).once('value', function(itemSnapshot) {
itemSnapshot.forEach(function(itemSnapshot) {
var itemData = itemSnapshot.val()
console.log('post snapshot'+ itemSnapshot);
updateObject['posts/'+postID+'/items/'+oldProductID] = null
updateObject['posts/'+postID+'/items/'+newProductID] = itemData
});
});
})).then(function(results) {
// put progress update in .then, and return the results
progress(75);
return results;
});
});
}).then(function() {
// Move to next item
return console.log('hey look here'+updateObject['posts/'+postID+'/items/'+newProductID]);
return firebaseRoot.update(updateObject, function(error) {
if (error) {
console.log("Error updating data:", error);
reject()
} else {
progress(100);
// resolve();
console.log('four');
}
});
});
// Finish the task asynchronously
setTimeout(function() {
reject();
}, 10000);
});
And the output is:
one
two
three
hey look hereundefined
post snapshot[object Object]
post snapshot[object Object]
post snapshot[object Object]
post snapshot[object Object]
post snapshot[object Object]
post snapshot[object Object]
post snapshot[object Object]
post snapshot[object Object]
Any and all help is super appreciated.
You need to change your .then from (now changed in the question, but the code originally had this)
}).then(function(updateObject) {
to
}).then(function() {
So that your code always updates the updateObject declared in the new Queue callback
also, the first line in each then needs to have a return added
so, instead of
userReceiptMetrics.child(userID).child('receipts').child(receiptID).child('items').child(oldProductID).once('value', function(oldSnapshot) {
you have
return userReceiptMetrics.child(userID).child('receipts').child(receiptID).child('items').child(oldProductID).once('value', function(oldSnapshot) {
The progress calls need to be put at the end of the .once callbacks
over all, the code should look like (removed most of the code that's correct, hope this is understandable
var queue = new Queue(productUpdateQueue, function(data, progress, resolve, reject) {
// removed for brevity
var updateObject = {};
// removed for brevity
clicks.child('VigLink').orderByChild('item').equalTo(oldProductID).once('value', function(cuidSnapshot) {
// removed for brevity
progress(12);
}).then(function() {
return userReceiptMetrics.child(userID).child('receipts').child(receiptID).child('items').child(oldProductID).once('value', function(oldSnapshot) {
// removed for brevity
progress(25);
});
}).then(function() {
return userReceiptMetrics.child(userID).child('shops').child(oldProductID).once('value', function(oldSnapshot) {
// removed for brevity
progress(50);
});
}).then(function() {
return posts.orderByChild('items').equalTo(oldProductID).once('value', function(postSnapshot) {
// use Promise.all and Array#map to wait for all these queries to finish
return Promise.all(postSnapshot.map(function(postSnapshot) {
var postID = postSnapshot.key;
return posts.child(postID).child('items').child(oldProductID).once('value', function(itemSnapshot) {
itemSnapshot.forEach(function(itemSnapshot) {
var itemData = itemSnapshot.val()
updateObject['posts/'+postID+'/items/'+oldProductID] = null
updateObject['posts/'+postID+'/items/'+newProductID] = itemData
});
});
})).then(function(results) {
// put progress update in .then, and return the results
progress(75);
return results;
});
});
}).then(function() {
// Move to next item
console.log(updateObject);
// removed for brevity
});
// Finish the task asynchronously
setTimeout(function() {
reject();
}, 10000);
});
So I finally figured out how to do this. I was having a problem passing the object from step to step but what I really wanted to do was create the object step by step. So I created the object outside of the promise chain and built it step by step. One of the main obstacles here was to get my loops to complete and then move on to the next promise in the chain. In order to do that, I used Promise.all() to return the results.
It works and now I know more about how promises work. If this can help you please take it:
var queue = new Queue(productUpdateQueue, function(data, progress, resolve, reject) {
var incomingUpdateData = data;
var receiptID = incomingUpdateData.receiptID;
var userID = incomingUpdateData.userID;
var oldProductID = incomingUpdateData.oldProductID;
var newProductID = incomingUpdateData.newProductID;
var newReceipt = incomingUpdateData.newReceipt;
var postID = "-KZOO0UII67uOmYo6DJh";
var postKeys = [];
var updateObject = {};
updateObject['usersPrivate/'+userID+'/receipts/'+receiptID+'/items/'+oldProductID] = null;
updateObject['usersPrivate/'+userID+'/receipts/'+receiptID+'/items/'+newProductID] = newReceipt;
return clicks.child('VigLink').orderByChild('item').equalTo(oldProductID).once('value', function(cuidSnapshot) {
return cuidSnapshot.forEach(function(cuidSnapshot) {
var cuid = cuidSnapshot.key;
updateObject['clicks/VigLink/'+cuid+'/item'] = newProductID;
progress(10);
});
}).then(function() {
return userReceiptMetrics.child(userID).child('receipts').child(receiptID).child('items').child(oldProductID).once('value', function(oldSnapshot) {
var data = oldSnapshot.val()
updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/items/'+oldProductID] = null
updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/items/'+newProductID] = data
if (data != null) {
updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/itemIDs/'+newProductID] = now
updateObject['userReceiptMetrics/'+userID+'/receipts/'+receiptID+'/itemIDs/'+oldProductID] = null
};
progress(25);
});
}).then(function() {
return userReceiptMetrics.child(userID).child('shops').child(oldProductID).once('value', function(oldSnapshot) {
var data = oldSnapshot.val()
updateObject['userReceiptMetrics/'+userID+'/shops/'+oldProductID] = null;
updateObject['userReceiptMetrics/'+userID+'/shops/'+newProductID] = data;
if (data != null) {
updateObject['userReceiptMetrics/'+userID+'/shopIDs/'+newProductID] = now;
updateObject['userReceiptMetrics/'+userID+'/shopIDs/'+oldProductID] = null;
};
progress(40);
});
}).then(function() {
progress(55);
return posts.orderByChild('receipt').equalTo(receiptID).once('value');
}).then(function(postSnapshot) {
return postSnapshot.forEach(function(post) {
progress(70);
postKeys.push(post.key)
});
}).then(function() {
return Promise.all(postKeys.map(function(postKey) {
return posts.child(postKey).child('items').child(oldProductID).once('value', function(itemSnapshot) {
var itemData = itemSnapshot.val()
updateObject['posts/'+postKey+'/items/'+oldProductID] = null;
updateObject['posts/'+postKey+'/items/'+newProductID] = itemData;
});
})).then(function(results) {
progress(85);
return results;
});
}).then(function() {
return firebaseRoot.update(updateObject, function(error) {
if (error) {
console.log("Error updating data:", error);
reject()
} else {
progress(100);
resolve();
}
});
});
// Finish the task asynchronously
setTimeout(function() {
reject();
}, 10000);
});
We are constantly getting false positive issues from our JavaScript plugins regarding the function complexity and function length rules.
The reason is that we have functions that are written inside function and the outer functions get the issues.
I understand that technically the complexity looks at everything,
but isn't there a way of getting the plugin to look only at the functions themselves?
(other than marking it as false positive)
Server version 4.5.6
JavaScript plugin version 2.9
There is a complexity issue of rule "javascript:FunctionComplexity" (complexity=25) for the redeployCtrl function.
This is the code, as you can see the actual complexity is from the inner functions.
is there a way around this other than marking the issue as false positive (and losing the complexity issue for the inner functions) or writing a custom rule?
thanks.
function redeployCtrl($scope, utilService, $filter, $location, generalSettings, $uibModalInstance, $uibModal, $timeout,scheme) {
$scope.openStart = openStart;
$scope.isSubmitable = isSubmitable;
$scope.ipCheckbox = ipCheckbox;
$scope.deploy = deploy;
$scope.init = init;
$scope.cancel = cancel;
function init() {
$scope.scheme = scheme;
$scope.loading = 'false';
$scope.envSchemes = [];
$scope.isPermanent = false;
$scope.permanent = {};
$scope.scheme.Scheme.Description = null;
$scope.scheme.Scheme.ExpTime = null;
var max = generalSettings.CalendarEndDate;
$scope.maxDate = new Date();
$scope.maxDate.setMonth($scope.maxDate.getMonth() + max);
$scope.minDate = new Date();
$scope.minDate = $scope.minDate.setDate($scope.minDate.getDate() + generalSettings.MinExpirationDate);
$scope.dateOptions = {
'year-format': 'yyyy',
'starting-day': 1
};
utilService.post(generalSettings.serverPath + 'envscheme/ListSupervisors/', { })
.then(function (data) {
$scope.supervisors = data;
}).catch(function (data) {
utilService.setError(data.ExceptionMessage, "Failed to retrieve data", "img_error");
});
utilService.post(generalSettings.serverPath + 'envscheme/ListPermReasons/', { })
.then(function (data) {
$scope.permReasons = data;
}).catch(function (data) {
utilService.setError(data.ExceptionMessage, "Failed to retrieve data", "img_error");
});
}
function openStart() {
$timeout(function () {
$scope.startOpened = true;
});
}
function deploy(scheme, isPermanent) {
if (isPermanent) {
scheme.Scheme.ExpTime = '01/01/9999';
scheme.Scheme.ApprovedBy = $scope.permanent.approvedBy;
if ($scope.permanent.mainReason === 'Other') {
scheme.Scheme.Reason = $scope.permanent.customReason;
} else {
scheme.Scheme.Reason = $scope.permanent.mainReason;
}
} else {
$scope.scheme.Scheme.ExpTime = utilService.getFormattedDate($scope.scheme.Scheme.ExpTime);
}
$scope.loading = 'true';
utilService.post(generalSettings.serverPath + 'envscheme/ReCreateEnv', scheme)
.then(function (data) {
if (data.Success) {
utilService.alertAmpm("Deploy started successfuly", "Info", "img_information");
$location.path("/MyEnvironments");
}
else {
utilService.alertAmpm(data.Reason, "Failed to Re-Deploy", "img_error");
$scope.loading = 'false';
}
if (data.Reason.indexOf("Session was not found") < -1) {
sessionStorage.clear();
$scope.loading = 'false';
}
}).catch(function (data) {
utilService.setError(data.ExceptionMessage, "Failed to Re-Deploy", "img_error");
$scope.loading = 'false';
});
}
function isSubmitable(invalid, modules) {
if (!invalid) {
for (var i = 0; i < modules.length; i++) {
if (modules[i].ipchkBox) {
if (!modules[i].OS.Parameters.IP) {
return true;
}
}
}
return false;
}
return true;
}
function ipCheckbox(checkBox, name) {
if (!checkBox) {
var name1 = "ipText" + name;
$('[name=' + name1 + ']').val('');
$scope.scheme.Scheme.modules[name].OS.Parameters = new Object();
}
}
function cancel() {
$uibModalInstance.dismiss('cancel');
}
Roy.
These rules force the coding with less nested functions. They ignore some cases like IIFE or practices accepted in some frameworks (AMD, Angular). But that's obviously is not your case.
So if you think that this coding practice is not for you, the only thing you can do is to disable the rules (and may create custom rules counting only lines you want).
Ive got this template on the front end:
if tournament
.tournament
if round
each round
ul(class='round#{currentRound} of#{rounds}')
each match
li
each participant
if winner
.participant.winner
a(href='#')
span.participant-title #{displayName}
span.participant-number #{rank}
span.participant-id #{id}
span.participant-status #{status}
span.participant-round #{thisRound}
span.participant-match #{thisMatch}
else if pending
.participant
a(href='#')
span.participant-title Waiting...
span.participant-number xxx
span.participant-id #{id}
span.participant-status #{status}
span.participant-pending
span.participant-disagree #{disagree}
span.participant-round #{thisRound}
span.participant-match #{thisMatch}
else
.participant.loser
a(href='#')
span.participant-title #{displayName}
span.participant-number #{rank}
span.participant-id #{id}
span.participant-status #{status}
span.participant-round #{thisRound}
span.participant-match #{thisMatch}
else
h1#not-found Tournament Not Found
and this helper:
tournament: function(){
if (this.tournament) {
return true;
}else{
return false;
}
},
round: function() {
var tournament = this.tournament.brackets;
var rounds = tournament.length;
var results = [];
tournament.map(function(value, index){
var currentRound = index + 1;
results.push({rounds: rounds, currentRound: currentRound, matches: value});
});
return results;
},
match: function(){
return this.matches;
},
participant: function(){
var results = [];
this.map(function (value, index) {
var type = value['win'];
var obj = {
id: value['id'],
rank: value['id'].slice(0,3),
displayName: value['displayName'],
thisRound: value['round'],
thisMatch: value['match'],
status: type,
disagree: value['disagree']
};
if (value['disagree']) {
console.log("value:", value);
}
if (type === true || type === 'undetermined') {
obj.winner = true;
}else if (type === 'pending'){
obj.pending = true;
}else{
obj.loser = true;
}
results.push(obj);
});
return results;
}
The helper is getting ran everytime the tournament object changes... but the template only gets updated the first time my meteor method is called?
have you ever encoutered this before?
I can post my meteor method if that would help too.
Where I change data:
Meteor.call('submitWinner', winnerInfo, thisCampaign._id, Meteor.user().apiKey, function(error, result) {
// display the error to the user and abort
if (error){
return alert(error.reason);
}else{
// update css?
var updateWaiting = $('.last-submitted').closest('.participant');
// updateWaiting.html('<a href=#><span class=participant-title>Waiting...</span> <span class=participant-number>xxx</span></a>');
// updateWaiting.removeClass('undetermined')
$('#theaterMode').hide();
$('.swearBox').hide();
}
});