Why is my break statement only working on the first "if"? - javascript

I'm trying to make a prompt based todo list
At the moment I'm trying to add the part that will prompt the user to add to the array, which works, but then when I try to quit it just keeps asking.
Quit works on the first question - "What would you like to do?" but once I've said "new" then typed an item it won't let me quit.
// TO DO
let toDo = [];
let options = prompt("What would you like to do?")
while (options !== "quit") {
if (options === "quit") {
break;
}
if (options === "new") {
let options = prompt("add to do")
toDo.push(options);
}
}
console.log( toDo )

The break here is completely pointless. if (options === "quit") { will never pass because while (options !== "quit") { will have failed by that time.
Your problem is caused because you have two variables named options.
The first one (on line 4) is used to test if the loop should exit or not.
The second one (inside if (options === "new") {) is used to push something onto the toDo array and shadows the first one.
Don't redeclare options. Remove let from the second one and just assign a new value to the existing variable.

Please use this code, what you do wrong,
you declare options again
if (options === "new") if bad, it make an infinite loop when the value is not 'new' (or 'quit')
the while test is sufficient
// TO DO
let toDo = []
let options = prompt("What would you like to do?")
while (options !== "quit")
{
toDo.push(options)
options = prompt("add to do")
}
console.log( toDo )

I think you can simplify your logic, using just one prompt; when users click on OK the input will be added to the to-do list and when they click on Cancel you will stop prompting the user for input.
Furthermore, as you have to prompt the user at least once, it would make sense to use a do { ... } while () block.
const todoList = [];
let todoItem;
do {
todoItem = window.prompt('What do you want to add to your list?\n(click on "OK" to add an item or on "Cancel" to quit)');
if (todoItem !== null && todoItem !== '') todoList.push(todoItem)
} while (todoItem !== null)
// test
console.log(todoList);

Related

Object in jquery not set on submit

I would like to get inputs values of a form and place in an object (for an offer).
So i tried to place this code on submit :
$(document).ready(function(){
$('#formOffre').on('submit', function(e) {
e.preventDefault();
console.log(Offre); // give undefined in console
if ( typeof Offre == 'undefined'){
// if undefined, create object
var Offre = {
BuyerID: 1, //I will handle this later
Total: 0,
OffreItem: [] //array with json objects
};
Offre.OffreItem.id = 0;
console.log("object created");
for (i=0; i > Offre.OffreItem.id ; i++) {
Offre.OffreItem.modele = formOffre.modele.value;
Offre.OffreItem.longueur = formOffre.longueur.value;
Offre.OffreItem.hauteur = formOffre.hauteur.value;
Offre.OffreItem.qte = formOffre.qte.value;
Offre.OffreItem.rix = formOffre.prix.value;
console.log("getting parameters of inputs to offer");
}
} else {
//if object exists ony get informations of inputs
Offre.OffreItem.id = 0;
for (i=0; Offre.OffreItem.id < i; i++){
Offre.OffreItem.modele = formOffre.modele.value;
Offre.OffreItem.longueur = formOffre.longueur.value;
Offre.OffreItem.hauteur = formOffre.hauteur.value;
Offre.OffreItem.qte = formOffre.qte.value;
Offre.OffreItem.rix = formOffre.prix.value;
}
}
this is my code. when i click on submit for the first time, it go to the if statement and create the object. But when i click again, I go through the if statement like the object is not set.
i put a console log and in every case the object is undefined.
Can you someone help me please?
Thanks
You are checking Offre out side of scope in which it is defined .
enter coconsole.log(Offre); // give undefined in console
if ( typeof Offre == 'undefined'){
// if undefined, create object
var Offre = { //here is issue this should be above submit function
BuyerID: 1, //I will handle this later
Total: 0,
OffreItem: [] //array with json objects
};
Also make sure your page is maintaining state.
For you I have created example give a look. here
Hoping this will solve your problem.
Fiddle
The problem here is that you're defining your variable inside the function.
To simplify your code:
$('#formOffre').on('submit', function(e) {
if ( typeof Offre == 'undefined'){
var Offre = { }; // This variable is only accessible inside this function
} else {
//
}
}
The var Offre will define a variable within the scope of the function, the next time you run the function, a new variable with that name will be created (Meaning it will always be undefined initially)
To get around this, you can define your variable outside of the function:
var Offre;
$('#formOffre').on('submit', function(e) {
if ( typeof Offre == 'undefined'){
Offre = { }; // Notice that we're not creating a new variable here, just accessing the one defined above
} else {
//
}
}

JavaScript API Response - Check if variable exists

In an API response, I want to check if a variable exists. If it doesn't, I want to assign it a blank value:
if(!data3.fields[i+2].values.value[0]) {
data3.fields[i+2].values.value[0] = "";
} else {
break;
}
Error in the console is:
Uncaught TypeError: Cannot read property 'value' of undefined
This confuses me because I thought that's exactly what my if the statement was checking. Any ideas what's going on here?
The if check won't protect you from trying to use an undefined variable. In your instance the values property is undefined. If you wanted to test for that you would need to first check that specific property
if(data3.fields[i+2].values !== undefined && data3.fields[i+2].values.value[0]){
//do something with data3.fields[i+2].values.value[0]
}
additionally, if you are in a scenario where you don't even know if data3 exists (for example you are checking for the existence of a third party script, or something else in your environment) you would need to use the typeof operator to be safe. E.G.
if(typeof(ga) !== 'undefined'){ //typeof returns a string. This would be testing for google analytics on a page.
It doesnt work like PHP does (which checks the whole 'chain'). In your example, you actually check if .value[0] of values exists, but dont check if values exists. The full version should be:
if( data3 && && data3.fields[i+2] && data3.fields[i+2].values && !data3.fields[i+2].values.value[0]) {}
In your code ata3.fields[i+2].values is undefined, and you're trying to access value[0] of 'undefined'
Or slightly more simplefied, if you wand to test if d has a value, you have to make sure that a, b and c aldo have a value:
if( a && a.b && a.b.c && !a.b.c.d){ /* ... */ }
You can remove checks on the left side of the checks if you are sure those exist. E.g.: If you know that a.b always exist, you can simplefy:
if( a.b.c && !a.b.c.d){ /* ... */ }
If you really want to make sure the complete property chain is not undefined you have to check every single step and the later ones won't be executed if at least && condition is false.
if (data3 && data3.fields && data3.fields[i+2] && data3.fields[i+2].values && data3.fields[i+2].values.value && data3.fields[i + 2].values.value[0]) {
data3.fields[i + 2].values.value[0] = "";
} else {
break;
}
Another way would be to just do it and catch the exception:
try {
data3.fields[i + 2].values.value[0] = "";
} catch (e) {
break;
}
The error is telling you that data3.fields[i+2].values is undefined. You can't check for a property .value on undefined.
You'd need to verify each property/index belongs along the way if you always want that nested path to default to an empty string.
if (data3.fields[i+2] === undefined) {
data.fields[i+2] = {};
}
if (data3.fields[i+2].values === undefined) {
data3.fields[i+2].values = {};
}
if (data3.fields[i+2].values.value === undefined) {
data3.fields[i+2].values.value = [];
}
// and finally your empty string assignment
if (data3.fields[i+2].values.value[0] === undefined) {
data3.fields[i+2].values.value[0] = '';
}
Depending on your requirements, you might be able to get away with assigning a stub as soon as you know data3.fields[i+2] is undefined.
if (data3.fields[i+2] === undefined) {
data3.fields[i+2] = {
values: {
value: ['']
}
};
}

Javascript - any way to access child properties only if they exist?

I'm thinking it would be useful to have something like:
let data = { item : { subItem: { text: 'Nested thing' } } }
if(data.?item.?subItem.?text){
//do something
}
Which would be shorthand for
if( data && data.item && data.item.subItem && data.item.subItem.text )
Can this be done? What would this be called?
At the moment the way you are doing it is the best one (performance speaking, code clarity and debuggability), usually objects doesn't get that nested deeper.
A (worse) option would be to simply access the member and use a try/catch construct to otherwise continue.
However for the future there is a feature called optional chaining planned, which will directly offer the functionality you where talking about. As userqwert stated with babel-plugin-transform-optional-chaining (currently in alpha) one can use that feature now/in the short future.
Here's the function I use
getValue(element,path) {
"use strict";
if (!Array.isArray(path)) {
throw new Error("The first parameter must be an array");
}
for (var i = 0; i < path.length; i++) {
if (typeof element == "object" && typeof element[path[i]] != "undefined") {
element = element[path[i]];
} else {
return undefined;
}
}
return element;
}
For your example, should be called like so
getValue(data,['item','subItem','text']);
This has some draw back though... But does the job.
If you wanted you could use this and work out a way to make it work directly on the Object prototype.

Object reference not set to an instance of an object in View

I have following code in view(in javascript)
console.log("#Model.Sides.SingleOrDefault(a => a.Name == "B").Surfaces.Count");
it throws an exception
Object reference not set to an instance of an object
How to make that when an exception is thrown-nothing happened?
You just need to check your objects are initialized first. This logic should really be outside of your views.
#{
int count = 0;
//Check the model isnt null first
if (Model != null)
{
var side = Model.Sides.SingleOrDefault(a => a.Name == "B");
if (side != null)
{
//You can perform null check on surfaces here as well
count = side.Surfaces.Count;
}
}
}
<script>
console.log("#count");
</script>
You can try the following
#if(Model.Sides.SingleOrDefault(a => a.Name == "B").Any())
{
console.log("#Model.Sides.SingleOrDefault(a => a.Name == "B").Surfaces.Count");
}
else
{
console.log("0");
}
In your case there might be situation when there are no items in #Model.Sides
In that case you can use.
#if(Model.Sides.Any() && Model.Sides.SingleOrDefault(a => a.Name == "B").Any())
{
console.log("#Model.Sides.SingleOrDefault(a => a.Name == "B").Surfaces.Count");
}
else
{
console.log("0");
}
SingleOrDefault will return a null if the list does not contain exactly one item.
If your 'where' clause a.Name == 'B' does not return exactly one item then the result will be null.
So if your Sides list does not have just one 'B' (ie there are none or 2 or more than 2), the result of SingleOrDefault will be null and .Surfaces will give the error 'Object reference not set to an instance of an object`.
If you simply want a count of zero when there isn't just one B side, then use:
console.log("#(Model.Sides.SingleOrDefault(a => a.Name == "B") ?? new Side { Surfaces = new List<Surface>() }).Surfaces.Count");
where ?? means: if the left part is null, return this instead of null
and you create a dummy Side with an empty list so that Surfaces.Count == 0
Alternatively, use a variable:
#{
var side = Model.Sides.SingleOrDefault(a => a.Name == "B");
if (side == null)
{
#:console.log("none")
}
else
{
#:console.log(#side.Surfaces.Count);
}
}
As a cleaner alternative, you could use SelectMany() instead, something like (untested) :
Model.Sides.Where(a=>a.Name=="B").SelectMany(x=>x.Surfaces).Count()
then you don't need to worry about temp variables etc but will return the number of 'surfaces' for all 'B' sides, so may not be your requirement.
On Catch(e) do nothing:
This is generic that can suppress any error. Wrap the code you think can error with try catch, with catch doing nothing.
But this could lead into further problems, just be cautious with empty catch block.
ex:
try
{
//code that errors
}
catch (e)
{
;
}
//Continue

How to apply an ng-class when data is added dynamically (?)

I have an application running with Ionic/Angular, all I need is to apply a class which is from the animate.css library, I have here this function which is the one working once you call $scope.addLineToBetSlip() and I want that class that I mentioned working once you call that function:
$scope.addLineToBetSlip = function(line, row, type) {
$scope.picksCount = !$scope.picksCount;
var spreadSelected = (row.spreadSelected && type === 'spread'),
totalSelected = (row.totalSelected && type === 'total'),
moneyLineSelected = (row.moneyLineSelected && type === 'moneyline');
if (spreadSelected || totalSelected || moneyLineSelected) {
BetSlipFactory.remove(line, row, type);
}else {
BetSlipFactory.add(line, row, type);
}
return $scope.picksCount;
};
here is my wrong HTML:
UPDATE
just change my code, is working now but only the first time that {{betSlipCount}} chenges
<span class="badge badge-assertive animate infinite"
ng-class="{bounceIn: picksCount}">{{betSlipCount}}</span>
<i class="icon ion-code-download"></i>
the other way I see, is that {{betSlipCount}} is constantly changing, actually {{betSlipCount}} changes every time you call $scope.addLineToBetSlip(), so the other way is activating that class every single time that {{betSlipCount}} changes.
It's been a while since I've used ng-class but I'm pretty sure the syntax is:
ng-class="{'className': booleanVariable}"
(meaning you've got the class name and variable backwards)
(also you may want to try enclosing the class name in single quotes, though I'm not sure if that's necessary)
The boolean variable can be a function that returns a boolean variable ie:
ng-class="{'fadeIn': addLineToBetSlip()}"
But it doesn't appear that your function returns a boolean variable. You could have it toggle a boolean variable in $scope, and use that variable name instead of the function, or you could have the function return true.
But I'm also not sure why you wouldn't just always want the 'fadeIn' class active.
Maybe you could tell us more about what your code is supposed to do and what it is currently doing.
UPDATE
Controller Code:
//Intialize the boolean variable
$scope.picksCount = false;
$scope.addLineToBetSlip = function(line, row, type) {
var spreadSelected = (row.spreadSelected && type === 'spread');
var totalSelected = (row.totalSelected && type === 'total');
var moneyLineSelected = (row.moneyLineSelected && type === 'moneyline');
if (spreadSelected || totalSelected || moneyLineSelected)
{
BetSlipFactory.remove(line, row, type);
}
else
{
BetSlipFactory.add(line, row, type);
}
$scope.picksCount = !$scope.picksCount;
};
HTML Code:
<span class="badge badge-assertive animate infinite" ng-class="{'bounceIn': picksCount}">{{betSlipCount}}</span>
<i class="icon ion-code-download"></i>

Categories

Resources