How do I calculate income and expense in an expense tracker JavaScript - html

I'm trying to add the value of a checked radio button in an object in another function.
However there is nothing being added and no error returned.
I'm building an expense tracker and adding those value (either income or expense) is important in my calculation.
Nb: when I try to console.log in the function where i capture the checked value, it works perfectly but when i try to add that value to the array object in another function nothing is added.
const TransactionType = document.getElementsByName('selector');
addbtn.addEventListener('click', function() {
if (expense.value == '' || amount.value == '' || date.value == '') {
alert('Please fill all the fields!!!');
return;
} else {
const userExpense = {
id: generateID(),
type: getTransactionType(), // here is the problem nothing is added
date: date.value,
expense: expense.value,
amount: amount.value
};
userInput.push(userExpense);
localStorage.setItem('data', JSON.stringify(userInput));
location.reload();
}
});
function getTransactionType() {
TransactionType.forEach(item => {
if (item.checked) {
return item.value;
}
});
}
<!-- radio buttons to choose the type of transaction -->
<div class="container">
<h3>Select the type of transaction:</h3>
<ul>
<li>
<input type="radio" id="type-income" name="selector" value="income">
<label for="type-income">Income</label>
</li>
<li>
<input type="radio" id="type-expense" name="selector" value="expense">
<label for="type-expense">Expense</label>
</li>
<!-- <button onclick=" getTransactionType()">see value</button> -->
</ul>
</div>

The code is incomplete. There is no addbtn and no handling of displaying the localStorage
Why do you reload?
TransactionType.forEach(item => {
if (item.checked) {
return item.value;
}
});
does nothing.
The return statement is not interesting in a forEach.
Here is a simpler method: I use delegation.
There is no need to test that anything is checked because you use radios. It needs more code if you were using a checkbox.
const getTransactionType = () => document.querySelectorAll('[name=selector]:checked')[0].value;
document.querySelector('.container').addEventListener('click', () => {
console.log(getTransactionType())
})
<!-- radio buttons to choose the type of transaction -->
<div class="container">
<h3>Select the type of transaction:</h3>
<ul>
<li>
<input type="radio" id="type-income" name="selector" value="income">
<label for="type-income">Income</label>
</li>
<li>
<input type="radio" id="type-expense" name="selector" value="expense">
<label for="type-expense">Expense</label>
</li>
</ul>
</div>

Related

Retaining response data in multiple checkboxes (Vue.js)

Iam new to vue. So iam trying to experiment requests and response through web servers. I have mutiple checkboxes as shown:
<li>
<div class="config-label">Photoshop IRB</div>
<div class="config-value">
<input
type="checkbox"
class="rounded text-light mr-3 bigger-checkboxes"
value="photoshop"
v-model="checkedCategories"
/>
</div>
</li>
<li>
<div class="config-label">Flashpix</div>
<div class="config-value">
<input
type="checkbox"
class="rounded text-light mr-3 bigger-checkboxes"
value="flashpix"
v-model="checkedCategories"
/>
</div>
</li>
Multiple checkboxes this way. The script is:
export default{
data(){
return {
checkedCategories : []
};
},
created() {
this.getExtractionConfig().then((data) => {
this.checkedCategories = data;
});
},
Now how do i retain the values of the checkboxes from the response ?
Ohkay, after debugging i found the solution for the silly lapse on my side. I had to select the key in data. So it was :
created() {
this.getExtractionConfig().then((data) => {
this.checkedCategories = data.selected_categories;
});

react safari can't focus on input when clicked

I'm creating a search bar like so:
<form
id="search-bar-form"
onSubmit={e => {
e.preventDefault();
}}
>
<div id="search-bar-div">
<input
onChange={async e => {
console.log("I was changed");//debug
// Set the search term
setSearchTerm(e.target.value);
// Fetch results
await debouncedSearch(e.target.value);
}}
onKeyUp={onKeyUp}
type="text"
name="search"
id="search-bar"
aria-label="search"
value={searchTerm}
list="search-bar-autocomplete"
autoComplete="off"
placeholder={`🔍 ${t('searchbar.default-value')}`}
/>
<div>
<ul id="search-bar-autocomplete">
{searchResults &&
searchResults.length > 0 &&
searchResults.map((result, index) => (
<li
key={index}
style={
selectionIndex === index
? {
backgroundColor: '#e8e8e8',
}
: null
}
onClick={() => {
const selectedItem = searchResults[index];
setSearchTerm(selectedItem.name);
handleItemSelected(selectedItem);
}}
>
{result.name}
</li>
))}
</ul>
</div>
</div>
</form>
In Safari, and Safari only, I am not able to click in the input at all; I don't even see the cursor in there.
This is not the same as this question, because in this question the input can be selected and the cursor appears but they can't type. Even though it's not the same problem I did try the solution suggested in that question, which is to add the propertyy -webkit-user-select:textto the input, and it didn't work.
Question: why can't I focus in my input and how do I make it possible?
I propose user-select: text;. The webkit version is a polyfill.

Failure handler in Google Apps Script receives object different from what is thrown on server side

My app sends submitted form data to this server-side function:
function processFormData(data)
{
data = JSON.parse(data);
// validate data
var errorObject = {},
potholeErrors = createErrorObjectFor('pothole'),
intervalSizeErrors = createErrorObjectFor('intervalSize');
// make sure numbers are actual numbers and not NaN's.
if (!validateNumber(data.potholeWidth))
{
potholeErrors.messages.push(errorTypes.NOT_A_NUMBER);
errorObject.potholeWidth = potholeErrors;
}
if (!validateNumber(data.intervalSize))
{
intervalSizeErrors.messages.push(errorTypes.NOT_A_NUMBER);
errorObject.intervalSize = intervalSizeErrors;
}
// make sure numbers are within their respective bounds (handled by handleErrors())
errorObject = handleErrors(data, errorObject);
// if intervalSize doesn't divide potholeWidth, make it so
if (data.potholeWidth % data.intervalSize > 0) data.potholeWidth = nextMultiple(data.intervalSize, data.potholeWidth);
// if there is anything in errorObject, throw it
if (Object.getOwnPropertyNames(errorObject).length != 0)
{
Logger.log('errorObject == ' + JSON.stringify(errorObject, null, '\t'));
throw errorObject;
}
// createSpreadsheet
return createSpreadsheet(data.spreadsheet, data.potholeWidth, data.intervalSize);
}
which, upon success, does exactly what it's supposed to do. However, when end-user enters any invalid input, the object the server-side throws back is different than the one they end up getting. I tried entering a pothole width that was too small. When I inspected Logger on server-side, I saw this correct output:
however, in the Developer console, I see:
The code that communicates data to the server looks like:
function updateURL(url)
{
// activate button
$('#input[type="submit"]').prop('disabled', '');
// change href of #spreadsheetLink
$('#spreadsheetLink').attr('href', url);
// unhide the link's container if hidden
if ($('#spreadsheetLink').parent().hasClass('hidden')) $('#spreadsheetLink').parent().removeClass('hidden');
// hide the 'Loading...' element
if (!$('#loading').hasClass('hidden')) $('#loading').addClass('hidden');
}
function emailLink()
{
google.script.run.withSuccessHandler(function() {
$('#emailLink').next().text('E-mail message has been sent!');
$('#emailLink').prop('disabled', 'disabled');
}).emailLink($('#spreadsheetLink').attr('href'));
}
function handleFails(failData)
{
var DEBUG = true;
if (DEBUG) console.log('failData == ' + JSON.stringify(failData, null, '\t'));
// hide 'Loading...' element
if (!$('#loading').hasClass('hidden')) $('#loading').addClass('hidden');
// for now, let's ignore any Errors/TypeErrors.
if ((!failData instanceof Error) && (!failData instanceof TypeError))
{
// for now, if there were any errors with any of the fields, simply mark them as .invalid
if ((failData.potholeWidth) && (failData.potholeWidth.messages.length > 0))
{
if (!$('#potholeWidth').hasClass('invalid')) $('#potholeWidth').addClass('invalid');
}
if ((failData.intervalSize) && (failData.intervalSize.messages.length > 0))
{
if (!$('#intervalSize').hasClass('invalid')) $('#intervalSize').addClass('invalid');
}
}
}
function submitFormData()
{
// hide spreadsheetLink container if not already done, and clear its <span> element if not already clear
var spreadsheetLinkContainer = $('#spreadsheetLink').parent(),
spanElement = $('spreadsheetLinkContainer').find('span');
if (!$(spreadsheetLinkContainer).hasClass('hidden')) $(spreadsheetLinkContainer).addClass('hidden');
if ($(spanElement).text() != '') $(spanElement).text('');
// get all data
var potholeWidth = parseNumberField('potholeWidth'),
intervalSize = parseNumberField('intervalSize') || defaults.get('intervalSize'),
concaveEdges = $('input[name="concaveEdges"]').filter(function() { return $(this).prop('checked'); }).next().text() === 'Yes',
spreadsheetName = parseField('spreadsheetName') || defaults.get('spreadsheetName');
// make button inactive
if (($(this).prop('tagName')) && ($(this).prop('tagName').toLowerCase() == 'input')) $(this).prop('disabled', 'disabled');
// show "Loading..." element
if ($('#loading').hasClass('hidden')) $('#loading').removeClass('hidden');
// submit this data to the server
google.script.run.withSuccessHandler(updateURL).withFailureHandler(handleFails).processFormData(JSON.stringify({
potholeWidth: potholeWidth,
intervalSize: intervalSize,
concaveEdges: concaveEdges,
spreadsheet : spreadsheetName
}));
}
and the HTML looks something like this:
<form>
Place straightedge/yardstick along width of pothole such that it points at the corners, <a class="showImage">like this</a>
<span class="row">
<label class="firstColumn seventeenTwentieths">Pothole width (in inches): </label>
<input type="text" class="secondColumn tenth numberField" id="potholeWidth" required />
</span>
<span class="rowTight">
<label class="firstColumn seventeenTwentieths">Interval size (in inches, default 1 inch): </label>
<input type="text" class="secondColumn tenth numberField" id="intervalSize" value="1" />
</span>
<div class="rowTight">
<label class="firstColumn">Do any of the edges intersect the straightedge/yardstick other than at the corners?</label>
<div class="secondColumn">
<span>
<input type="radio" name="concaveEdges" id="yesConcaveEdges" />
<label for="yesConcaveEdges">Yes</label>
</span>
<br>
<span>
<input type="radio" name="concaveEdges" id="noConcaveEdges" checked />
<label for="noConcaveEdges">No</label>
</span>
</div>
</div>
<span class="rowTight">
<label class="firstColumn half">Spreadsheet name: </label>
<input type="text" class="secondColumn nineTwentieths" id="spreadsheetName"/>
</span>
<span class="center row">
<button class="center" id="clearForm">Clear</button>
<input type="submit" class="center action" value="Create spreadsheet" />
</span>
</form>
<span id="loading" class="row center fullWidth hidden">
Loading...
</span>
<span class="row center fullWidth hidden">
Here is your spreadsheet
<button id="emailLink">E-mail me the link</button>
<span></span>
</span>
What is that object the client actually gets and how to make sure that it's getting the object the server actually throws?
I fixed it.
What I did
In code.gs
Instead of simply throw errorObject;, I said throw JSON.stringify(errorObject);
In JavaScript.html file
in handleFails(), I converted the string the server-side threw back into object (failData = JSON.parse(failData)) to use it. It outputted it correctly, and all is well.
What I learned
Any time the server is either giving or receiving data, it MUST be in the form of a string! (Use JSON.stringify() to make that data a string!)

How to make Razor not display special characters as html

The page I'm working on displays content from a database in readonly input box. My problem is that it's displaying any special characters as the html code (ie: & displays as &). How do you get the code to display properly?
I'm using QuerySingle to connect to the database, don't know if that makes a difference. I'm new to using Razor. Any help is much appreciated.
Code in question:
var queryloan = "SELECT * FROM loans WHERE LoanId = #0";
var queryloandata = db.QuerySingle(queryloan, queryformstatus_submitted.doc_loanid);
<form class="jotform-form" action="submit-form.cshtml?isadmin=#(isadmin)&loanid=#(loanid)" method="post" name="form_30905105572145" id="30905105572145" accept-charset="utf-8">
<input type="hidden" name="formID" value="30905105572145" />
<input type="hidden" name="doc_id" value="#doc_id" />
<div class="form-all">
<ul class="form-section">
<li id="cid_3" class="form-input-wide">
<div class="form-header-group">
<h2 id="header_3" class="form-header">
Borrower Sources & Uses Summary
</h2>
#if (queryformstatus_submitted.doc_approval == "Pending Approval" || queryformstatus_submitted.doc_approval == "Approved")
{
<text><br />
<br />
<div class="error">
This form has already been submitted and cannot be edited. It is for reference only.</div></text>
}
#if(userid != queryformstatus_submitted.doc_userid){
<text><br/><br/><div class="error">You may not edit this form. It is for reference only.</div></text>
}
</div>
</li>
<li class="form-line" id="id_4">
<label class="form-label-left" id="label_4" for="input_4">
1. Property Name:
</label>
<div id="cid_4" class="form-input">
<input type="text" class=" form-textbox" id="input_4" name="q4_1Property" size="40" value="#Helpers.checkEmptyPreFill(queryinputvalue,"q4_1Property",queryloandata.LoanName)"/>
</div>
</li>
I'm not sure but I believe it may be something in this helper function that's causing the html code:
#helper checkEmptyPreFill(IEnumerable<dynamic> queryinputvalue, string field_id, string defaultval, int cloned = 0) {
var reqValue = queryinputvalue.FirstOrDefault(r => r.field_name.Equals(field_id));
var return_value = "";
if(reqValue != null){
return_value = reqValue.field_data;
} else {
return_value = defaultval;
}
if(cloned == 1){
return_value = "";
}
#return_value
}
The razor helper returns a HelperResult object so you'll have to convert it to a string before you can call HtmlDecode on it. Replace:
#Helpers.checkEmptyPreFill(queryinputvalue,"q4_1Property",queryloandata.LoanName)
with the following:
#HttpUtility.HtmlDecode(Helpers.checkEmptyPreFill(queryinputvalue,"q4_1Property",queryloandata.LoanName).ToString())
I would also suggest that you move some of the logic and data access code out of your view and into a controller but this should give you the result that you'e after.

Why are my inputs not resetting?

The below code generates several forms depending on data returned from the server. Everything generates fine, but after clicking on an AnswerOpenQuestion button the input does not clear/reset. What's going on here?
angularJs code:
var availableInterviewController = function($scope, $http) {
// define initial model
$scope.interviews = [];
// retrieve available interviews
$http.get('/api/UserInterviewsApi/AvailableInterviews')
.success(function(data) {
// update interviews
$scope.interviews = [];
$scope.interviews = data;
});
// define open question answer selection
$scope.Answer = "";
// define multiple choice selection
$scope.selectedChoice = "";
// define answer open question button
$scope.AnswerOpenQuestion = function() {
$scope.Answer = ans;
alert(q.Question + ' and ' + $scope.Answer);
$scope.Answer = ''; // <---This is not clearing/resetting the HTML form inputs
};
// define answer multiple choice button
$scope.AnswerMultipleChoice = function() {
//
};
};
// assign the new controller to the main angular app
myAngApp.controller('availableInterviewCtrl', availableInterviewController);
Html code:
<form class="form-group" ng-repeat="q in inter.Questions">
<fieldset style="display: inline-block;">
<legend>Question {{$index + 1}}</legend>
<!--Open Ended-->
<div class="form-group" ng-show="q.MultipleChoices.length === 0">
<label for="{{'quest-' + $index}}">
<strong class="text-info">{{q.Question}}</strong><br />
</label>
<input name="openQuestion" id="{{'quest-' + $index}}" type="text"
class="form-control" ng-model="Answer" />
<button ng-click="AnswerOpenQuestion()">Answer</button><br />
<span class="text-info">
asked by {{q.AskedByUserName ==
'Administrator' ? 'staff' : q.AskedByUserName}}
</span>
</div>
<!--Multiple Choice Question-->
<div class="form-group" ng-show="q.MultipleChoices.length > 0">
<label for="{{'quest-' + $index}}">
<strong class="text-info">{{q.Question}}</strong>
</label>
<div>
Select an answer:
<label ng-repeat="x in q.MultipleChoices">
<input name="currentChoice" type="radio" value="{{x.Id}}"
ng-model="selectedChoice" />
{{x.Choice}}
</label>
<button ng-click="AnswerMultipleChoice()">Answer</button><br />
<span class="text-info">
asked by {{q.AskedByUserName ==
'Administrator' ? 'staff' : q.AskedByUserName}}
</span>
</div>
</div>
</fieldset>
</form>
UPDATE - Solution
AngularJs:
// define open question answer selection
$scope.OpenAnswer = { Answer: '' };
// define answer open question button
$scope.AnswerOpenQuestion = function (q, ans) {
$scope.OpenAnswer.Answer = ans;
alert(q.Question + ' and ' + $scope.OpenAnswer.Answer);
// clear the input
$scope.OpenAnswer.Answer = '';
};
Html:
<input id="{{'quest-' + $index}}" type="text"
class="form-control" ng-model="OpenAnswer.Answer" />
Don't use the scope as a model instead make an object that wraps the data model and assign it to a property of the scope.
$scope.myModel = {Answer:''}
Also don't use value in most cases ngmodel is all you need for two way binding.
In js strings are immutable so the original reference is not being updated instead a new string is being made, the digest cycle won't see this as a change to the original string.