LocalStorage drag previous saved array - javascript

I'm coding a currency converter that save every conversion that the user make and displayed. When i make the first conversion is fine. When i make the second it show the first one and the second, instead of only the second, like a to do list. Also i tried to use a constructor but i dont think that is the problem. If anyone can give me any help, that would be awesome!. Thx.
function calculo(){
resultado=(cantidad/monedaVal1)*monedaVal2;
$('#res').html('Obteniendo conversion...');
$('#res').fadeOut(500)
.fadeIn(500)
.fadeOut(500)
.fadeIn(500,function(){
$('#res').html(cantidad+' '+monedaText1+' = '+resultado.toFixed(2)+' '+monedaText2);
});
almacen();
}
class conversion {
constructor(monto, origen, destino, final) {
this.monto = monto;
this.origen = origen;
this.destino = destino;
this.final = final;
}
}
function almacen(){
cambios.push(new conversion(cantidad,monedaText1,monedaText2,resultado));
guardarCambio(cambios);
listarCambio(cambios);
}
function guardarCambio(cambios) {
let cambio = cargarCambio();
cambio.push(cambios);
localStorage.setItem('test', JSON.stringify(cambios));
}
function cargarCambio() {
if (localStorage.getItem('test')) {
return JSON.parse(localStorage.getItem('test'));
}
return [];
}
function listarCambio(cambios){
$.each(cambios, function (i) {
$('#conversiones').append('<tr><td>'+cambios[i].monto+'</td><td>'+cambios[i].origen+'</td><td>'+cambios[i].destino+'</td><td>'+cambios[i].final+'</td></tr>');
})
}

Related

Tiles dont turn right

I am making a website, http://phaidonasgialis.xyz. I want to make the tiles to turn and every other tile back. Until now it works except one small bug, the tile that you pressed does not turn back until you click second time.Any help would be thankful.
Here is the code:
$(document).ready(function() {
var previous = [];
$('.flip-card').each(function(i, obj) {
$(this).click(function() {
if ($(this).find('.flip-card-inner').hasClass('flip-card-transform')) {
$(this).find('.flip-card-inner').removeClass('flip-card-transform');
} else {
$(this).find('.flip-card-inner').addClass('flip-card-transform');
previous.push(this);
if (previous.length >= 2 && previous[previous.length - 2] != previous[previous.length - 1]) {
for (var i = 0; i < previous.length; i++) {
if ($(this).find('.flip-card-inner').hasClass('flip-card-transform')) {
$(previous[i - 1]).find('.flip-card-inner').removeClass('flip-card-transform');
console.log("2")
} else {
$(this).find('.flip-card-inner').addClass('flip-card-transform');
console.log("3")
}
}
}
}
});
});
If I understand your question correctly, you would like a card to flip back automatically after a certain period of time? If so then you just should set a Timeout and remove the class flip-card-transform from .flip-card-inner.
Aside note: you should definitely optimize your code by using a variable instead of doing $(this).find('.flip-card-inner')– converting this to jQuery object and searching trough its children every time when you need your flip-card-inner. Also instead of $('.flip-card').each(...) you could directly use $('.flip-card').click(...). And also as Harun Yilmaz suggested in his comment you don't need previous as an array...
So something like this should work:
$(document).ready(function () {
var previous
var timeout
$('.flip-card').click(function () {
var cardInner = $(this).find('.flip-card-inner')
if (cardInner.hasClass('flip-card-transform')) {
cardInner.removeClass('flip-card-transform')
clearTimeout(timeout)
} else {
cardInner.addClass('flip-card-transform')
// Set a Timeout
timeout = setTimeout(function () {
cardInner.removeClass('flip-card-transform')
}, 2000) // set whatever time sutable for you
// Also as Harun Yilmaz suggested in his comment you don't need previous as an array
if (previous && previous.hasClass('flip-card-transform')) {
previous.removeClass('flip-card-transform')
}
previous = cardInner
}
})
})

call user function in foreach loop

i have understand that i need to change the global scope of this, because in the loop this refers to the window object. But if i try to define a variable in my foreach loop via a function its not working and i dont know why although my functio returns the correct value :(
// simple class for xml import
function io() {
this.vertexes = [];
this.getVertexByID = function(id) {
this.vertexes.forEach(function(entry) {
if (id == entry.id) {
// correct element found, displayed and returned
console.log(entry);
return entry;
}
});
}
this.importXML = function(xmlString) {
cells = this.xmlToJson(xmlString);
var parent = graph.getDefaultParent();
var _this = this;
graph.getModel().beginUpdate();
try {
// addEdges
cells.XMLInstance.Edges.Relation.forEach(function(entry) {
// both will be empty but i dont understand why :(
fromVertex = _this.getVertexByID(entry.fromNode);
toVertex = _this.getVertexByID(entry.toNode);
var e1 = graph.insertEdge(parent, null, '', fromVertex, toVertex);
});
} finally {
graph.getModel().endUpdate();
}
}
Returning a value in a forEach callback has no effect. It certainly is not the return value of the function that the forEach is part of.
So change this:
this.vertexes.forEach(function (entry) {
if(id==entry.id){
//correct element found,displayed and returned
console.log(entry);
return entry;
}
});
to this:
return this.vertexes.find(function (entry) {
return id==entry.id;
});

Why does my WinJS Grouped Binding List play musical chairs with some items?

I'm creating a grouped list of my pupils as per this example: http://msdn.microsoft.com/en-us/library/windows/apps/hh465464.aspx
The actual code for creating the grouping as well as the HTML are almost identical (safe for name changes).
I'm then push()ing some items into the original List() which then also updates the GroupedList(). That part works fine.
However, what I'm seeing is this:
This list should be grouped by firstnames (on display is "Lastname, Firstname"). What I'm seeing here is that item #1 should be in "S", #3 should be in "A" and #6 should be in "I".
The only thing that I'm doing different from the example is the DataSource, insofar as I'm push()ing an actual WinJS Class in there (with getter and setter functions for the attributes displayed in the List).
However, the getGroupKey(dataItem) and other grouping functions are working as they should, i.e. return the proper values.
Any ideas? Because otherwise I'd have to look at using two arrays (one being the List() and another the array where the class instances live) for which I'd then have to program sync routines to keep the data consistent and that's something I actually wanted to escape from...
Code follows below, relevant snippets only.
Defining the Lists and grouping functions:
function compareGroups(leftKey, rightKey) {
return leftKey.charCodeAt(0) - rightKey.charCodeAt(0);
}
function getGroupKey(dataItem) {
return dataItem.lastname.toUpperCase().charAt(0);
}
function getGroupData(dataItem) {
return {
title: dataItem.lastname.toUpperCase().charAt(0)
};
}
var pupilsList = new WinJS.Binding.List({ binding: true });
var groupedPupilsList = pupilsList.createGrouped(getGroupKey, getGroupData, compareGroups);
Where the Data comes from:
var Schueler = WinJS.Class.define(function (original, id, firstname, lastname, tutor_id, picture, email, phone, notes, birthday, classes) {
var that = this;
this._classnames = new Array();
if (original) {
[... irrelevant part snipped ...]
});
} else {
var row = id;
this._id = row.rowid;
this._firstname = row.firstname_enc;
this._lastname = row.lastname_enc;
this._tutor_id = row.tutor_id;
this._picture = row.picture_enc;
this._email = row.email_enc;
this._phone = row.phone_enc;
this._notes = row.notes_enc;
this._birthday = row.birthday_enc;
this._guid = row.guid;
this.updateClassnames();
}
},
{
id: {
get: function () {
return this._id;
},
set: function (id) {
this._id = id;
}
},
firstname: {
get: function () {
return this._firstname;
},
set: function () {
//TODO
}
},
lastname: {
get: function () {
return this._lastname;
},
set: function () {
//TODO
}
},
[... irrelevant parts snipped ...]
classnames: {
get: function () {
return this._classnames.join(", ");
},
set: function (names) {
this._classnames = names;
}
},
updateClassnames: function () {
var that = this;
SQLite3JS.openAsync(DataLayer.db_path)
.then(function (db) {
var sql = "SELECT Classes.name_enc FROM Classes JOIN Classes_Pupils ON Classes.rowid = Classes_Pupils.class_id JOIN Pupils ON Classes_Pupils.pupil_id = Pupils.rowid WHERE Pupils.rowid = {0};".format(that._id);
return db.allAsync(sql)
.then(function (results) {
db.close();
var names = new Array();
for (var i = 0; i < results.length; i++) {
names.push(results[i].name_enc.toString().decrypt());
}
that.classnames = names;
DataLayer.PupilsList.dispatchEvent("reload");
}, function (error) {
if (error.message.indexOf("database is locked") > -1) {
console.log("DB locked, will try again in 50 ms");
window.setTimeout(that.updateClassnames(), 50);
}
});
});
}
},
{
reconstructAll: function () {
DataLayer.retrieveSeveralRows("Pupils", function (results) {
for (var i = 0; i < results.length; i++) {
DataLayer.PupilsList.push(new Schueler(false, results[i]));
}
});
}
});
WinJS.Namespace.define("DataLayer", {
Schueler: Schueler
});
Workflow is as follows: First empty lists are created, then another routine checks for DB availability. As soon as that routine gives a green light, Schueler.reconstructAll() is called.
DataLayer.retrieveSeveralRows(table, callback) is a wrapper function for a call to the SQLite database, essentially doing a SELECT * FROM Pupils and returning the results to the callback function.
This callback then creates a new instance of the Schueler() class and pushes that to the list.
Addendum: If I use createSorted() everything is just dandy. Will use that for now.
Edit: As suggested by Kraig Brockschmidt, it seems to have indeed been a localization issues, so adding one line and modifying one function as follows fixes everything right up:
var charGroups = Windows.Globalization.Collation.CharacterGroupings();
function getGroupKey(dataItem) {
return charGroups.lookup(dataItem.lastname.toUpperCase().charAt(0));
}
I see that you're working with createSorted now, but there are a couple of other things you can do to diagnose the original issue.
First, try using some static data instead of populating your list dynamically.
Second, put some console.log output inside your getGroupKey and getGroupData functions so you can evaluate what you're returning, exactly.
The other thing I should mention is that the MSDN docs page shows code that isn't sensitive to all local languages. That is, using the first character of a string for sort order isn't always the right thing. There is an API in Windows.Globalization.Collation (http://msdn.microsoft.com/en-us/library/windows/apps/windows.globalization.collation.aspx) that is built to handle sort ordering properly. If you look at the [HTML ListView Grouping and Semantic Zoom sample][1], in the file groupeddata.js, you'll see how this is used. Offhand this shouldn't affect your data, but I wanted to mention it.

jQuery - add several textboxes

Im using this code:
jQuery.fn.update_textarea = function(test) {
$("#articles_textarea").html('');
for (i=0;i<test;++i) {
if (message[i]) { $("#articles_textarea").html('<textarea></textarea>'); }
else { message[i] = ''; $("#articles_textarea").html('<textarea></textarea>'); }
}
}
When im trying to add more then one, nothing happends but if i add 1 it works just as it should..
This is the "call"code
$("#articles_textarea").update_textarea(total);
This is variable total:
var total = parseFloat($(".testCounter").val()) + 5;
This is for calling only one textarea (the part that works):
$("#articles_textarea").update_textarea(1);
When i call one box it's working when i call several boxes nothing happends at all..
try with append method. .html() will remove the previous content
jQuery.fn.update_textarea = function(test) {
$("#articles_textarea").html('');
for (i=0;i<test;++i) {
if (message[i]) { $("#articles_textarea").append('<textarea></textarea>'); }
else { message[i] = ''; $("#articles_textarea").append('<textarea></textarea>'); }
}
}
Why you use jQuery.fn, when you don't use its functionality, whereas it works, only for the textareas with articles_textarea Id, you better do it using a simple function like:
function update_textarea(test) {
$("#articles_textarea").html('');
for (var i=0;i<test;++i) {
if (!message[i]){
message[i] = '';
}
$("#articles_textarea").append('<textarea></textarea>');
}
};
adding a new function to jQuery.fn is used to create new jQuery plugins, check this link for more info.
the other point was not using var i in your for loop which is not a good practice. Moreover both your if statement and the else, were the same, except message[i] = ''; part.
BTW if you want to do it using jQuery.fn, you better do it like:
jQuery.fn.update_textarea = function(test) {
this.html('');
for (var i=0;i<test;++i) {
if (!message[i]){
message[i] = '';
}
this.append('<textarea></textarea>');
}
};

document.write in function body

I have the following JavaScript function which receives coordinates and returns the nearest tube station:
function coord() {
var metro = new YMaps.Metro.Closest(new YMaps.GeoPoint(<?=getCoords($addr) ?>), { results : 1 } )
YMaps.Events.observe(metro, metro.Events.Load, function (metro) {
if (metro.length()) {
metro.setStyle("default#greenSmallPoint");
var firstStation = metro.get(0);
var tubest = (firstStation.text).split("метро ");
var tube = tubest[1];
if($("span#tubest").text() == '') {
$('.whiteover').hide();
}
} else {
if($("span#tubest").text() == '') {
$('.whiteover').hide();
}
}
});
}
The value which I need to output as a result of this function execution is the value of the "tube" variable (var tube = tubest[1];). Basically a simple document.write will work. Or a simple return value like:
var tubestation = coord();
However I'm not sure how to achieve this.
You can't have this function return the value, since you're using an observer pattern - which sets up an asynchronous logic to the code. Simply saying, at the time that your coord() function returns, the value is not there yet.
To deal with this, normally you would pass a callback function, then resume your computation there.
Declare your function as:
function coord(callback)
then, after you know the value you want, call the callback with the value:
callback.call(null, tube);
Do it after your if { ... } else { ... } so your callback gets called both on success and on failure (on failure it will pass undefined, you might want to correct it by declaring var tube = null before the if).
then, instead of:
tubestation = coord();
call it like this:
coord(function(tubestation) {
// continuation of your code here
});
You probably won't be able to use document.write since the time to use it would be long past, but you can set the value as the contents of an element that you already generated. You have jQuery in your tags, so it's quite easy:
coord(function(tubestation) {
$('#tube_station').text(tubestation);
});
assuming you have <div id="tube_station"/> somewhere in your HTML.
How about this simple add to that function?
function coord() {
var metro = new YMaps.Metro.Closest(new YMaps.GeoPoint(<?=getCoords($addr) ?>), { results : 1 } )
YMaps.Events.observe(metro, metro.Events.Load, function (metro) {
if (metro.length()) {
metro.setStyle("default#greenSmallPoint");
var firstStation = metro.get(0);
var tubest = (firstStation.text).split("метро ");
var tube = tubest[1];
$('div#myDivResult').html(tube)
if($("span#tubest").text() == '') {
$('.whiteover').hide();
}
} else {
if($("span#tubest").text() == '') {
$('.whiteover').hide();
}
}
});
}

Categories