AngularJS - Keep Checking Variable/Function - javascript

I would like to know what is the best way to keep checking a variable in AngularJS.
I made a simple clicker game where the user keeps gathering gold, so I need to be constantly checking the number of gold so I can perform some functions accordingly. The only thing I know is $interval, but I don't know if that's the best way since I have to write a number of seconds.
Thank you in advance.

Wherever your variable is stored (controller/directive):
$scope.goldAmount = 0; // or whatever initial value you so desire
Set a watch function
$scope.$watch('goldAmount', function(newAmount, oldAmount){
// Do something with the amount when it changes
});
$watch allows you to 'watch' any variable within your $scope and run a call back when it changes.
Docs can be found here:
https://docs.angularjs.org/api/ng/type/$rootScope.Scope

Related

How can I store a JavaScript variable in local storage?

So I have a JavaScript variable called addNumber which just adds a number by 1 to a div any time I click a button. But I'm using it on a website which has multiple pages, and every time I change pages, it resets the counter. I've used console.log() to check the variable multiple times, and it always resets back to zero any time I leave the page, even when I keep the tab open. This counter is kept at the top of the page for all to see, and I want it kept there in a navbar, kind of like the shopping cart on Amazon. Is there a way I can do something like that using only vanilla JavaScript?
Thank you.
You may find this link helpfull.
https://www.w3schools.com/jsref/prop_win_localstorage.asp
Quick answer you store key value pairs using a string tag to identify them:
localStorage.setItem("lastname", "Smith");
localStorage.getItem("lastname"); //this returns the string "Smith"
Edit: i do not recommend you doing this in a production enviroment. You should stick to the framework of the project. If the project has no framework or is just for school or learning purposes then i guess is a viable option.
You can store a variable in localStorage to access it somewhere else through
Try using:
function onClickevent(){
addNumber = addNumber +1
localStorage.setItem('counter', addNumber);
}
Then get it through
//Just assign it to your div
const getIt = localStorage.getItem('counter')
Here is some documentation on LocalStorage and how to use it :)
https://www.w3schools.com/jsref/met_storage_getitem.asp
https://blog.logrocket.com/localstorage-javascript-complete-guide/#:~:text=To%20get%20items%20from%20localStorage%2C%20use%20the%20getItem()%20method,in%20the%20browser's%20localStorage%20object.
The solution you can try is :
In the .js file at the end of all lines, type
window.localstorage.setItem("addNumber",addNumber);
The addNumber will be stored with an ID of addNumber.
To later retrieve, use :
window.localstorage.getItem("addNumber");
You may assign the above to a variable like
var number =....
Then console the number.
I hope this helps.

AngularJS for loop not waiting for modifications to $scope

I've been wracking my brain over this for a few days, so I figured it's time to finally ask somebody who actually knows what they're doing. ;)
I'm building an AngularJS app and getting an odd behavior when I'm iterating through a couple of my for loops. I'm trying to find the 'best' option to add to a list given a few possibilities, and so here's my general process for how I'd like to get it done:
The Idea:
1) add each possibility to the desination list, say $scope.list1
2) calculate the 'score' based on the state of the lists
3) remove the possibility from $scope.list1
4) repeat for all possibilities.
Here's the basic idea of what I'm running in my controller:
$scope.getSuggestions = function(){
//for each possibility to consider:
for(var i = 0; i < possibilities.length; i++){
//add the possibility to the scope as per usual
$scope.list1.push(possibilities[i]);
//calculate the score given the state of the scope
$scope.calculateScore();
//save the score in a new object on the scope
$scope.results.push({"option": possibilities[i],
"score": $scope.score
});
//remove the possibility to reset the scope back to its original state
$scope.list1.pop();
}
};
The Problem:
It seems as if my for loop is actually moving on to further iterations before the code has finished executing. My $scope.calculateScore() function may take a bit of time to run, and it seems like it's being ignored by the for loop. I'm not doing anything obviously asynchronous in that function; it's mostly other for loops based on the state of the $scope and some math to get a 'score'.
My question:
Why does Angular think it's okay to continue blazing through a for loop when the code inside hasn't finished executing? I see how it could make sense in certain cases, but in this one it's vital that everything happens in order, after the previous functions have finished. Do you all have any suggestions on how to make this work?
Note: You can see the code in its entirety by viewing the source at http://www.PlatTheLeague.com
The actual code for calculateScore() is in scripts/controllers/teamBuilderCtrl.js, where the function is called $scope.populateGamePredictions(). My initial tries at the suggestions are in the same file, called $scope.getChampSuggestions. To see the problem, drag an item from the list on the left to the box that says 'Their Top' and then click on the 'Champion Suggestions' tab. That tab should be populated with the results of $scope.results listed above in the pseudo-code, but it seems that the teamScore on my scope object isn't being set properly.
Cheers!
Maybe you have some logics that change the internal states of $scope from outside of AngularJS, maybe from some kinds of events from DOM, ajax callbacks, setTimeout ... In that case, $apply method can help. You can have more references of $apply from here: https://github.com/angular/angular.js/wiki/When-to-use-$scope.$apply()
As it turns out, The above idea works in the typical synchronous manner, as I've proved to myself in this plunker: http://plnkr.co/edit/9spVbf5JWx9Hnq53sHSV?p=preview
My issue arose from the fact that the data model being worked on by my calculateScore() function was not formatted exactly how I thought it would be (my own fault, thanks to the semi-complicated nature of the app...) which meant that the scores weren't being updated properly in the first place, though the code was running as expected.

KnockoutJS: Stop a particular property from setting dirty flag

With some help from StackOverflow community I was able to get my dirty flag implementation to work, based on this example: http://www.knockmeout.net/2011/05/creating-smart-dirty-flag-in-knockoutjs.html
It does exactly what I want, except for a single use case that I don't know how to solve.
Basically I have a select menu that gets automatically populated from the database. This select menu also has an option to make an Ajax call to my back end and have the list of options refreshed, database updated and return the result. This is where things get hairy for me.
First method works fine, however, it has to re-index and re-apply my entire viewModel and takes about 2-3 seconds, running on a local machine with 16gigs of ram and SSD.
jsondata.component.available_tags = result.available_tags;
ko.mapping.fromJS(jsondata, viewModel);
Second method also works, and pretty much instantaneous, however, it sets of isDirty() flag, which I would like to avoid, because this data is already coming from the database and I wont need to save it. I can not use isDirty.reset() method either, because if isDirty was set by something else before I clicked an menu option to update available_tags, it will reset that too. Which I would also like to avoid.
viewModel().component.available_tags(result.available_tags);
My question is: With the first method, can I force UI refresh with ko.mapping.fromJS() on a particular element and not entire dataset? Or, with a second method, can I avoid setting isDirty flag set when available_tags are updated? The twist is that I still need to keep available_tags as an observable, so the select menu is automatically generate/updated.
UPDATE: I was able to update mapping for that one single element with
ko.mapping.fromJS(result.available_tags, {}, viewModel().component.available_tags);
but that immediately set off isDirty flag... Argh
In addition to Tomalak's suggestions, which I totally agree with, maybe the toJSON method can help you out in similar cases where you don't want to split the model. If your dirty flag implementation uses ko.toJSON as a hash function, as Ryan Niemeyer's does, you can give your model (on which the dirty flag is active) a toJSON method, where you do something like this:
function MyObjectConstructor() {
this.someProperty = ko.observable();
this.somePropertyNotUsedInDirtyFlag = ko.observable();
}
MyObjectConstructor.prototype.toJSON = function () {
var result = ko.toJS(this);
delete result.somePropertyNotUsedInDirtyFlag;
return result;
};
Please be aware that this is also used to serialize the object in some other occassions, such as ajax calls. It's generally a handy function for removing computeds and such from your objects before using them in a different context.

Why won't my function follow my if/else conditions?

Here's the fiddle: http://jsfiddle.net/K5dsh/
I'm trying to make a simple calculator that evaluates the difference between the numbers its given, and gives an answer based on that. It has two problems:
1.) The answer my script gives is always the result of my 2nd else if statement, even if the input matches the conditions before it.
2.) The answer does not change even when there's a new input that should give a different result.
Does anyone see what the problems are? Thank you.
As Ivan pointed out, you're never updating the values of high, low and common with the values entered into the textboxes. You should be assigning the values inside the calculate function. See updated fiddle.
Also, you may want to invest some time into learning a framework like Knockout.js. It makes data-binding HTML form elements to JavaScript view models incredibly simple.
Your variables are defined only once. You should change it so that every time your button is clicked, it grabs the new variables. Here is an example: http://jsfiddle.net/Vd8n4/
Your values aren't being updated.
Here's how I would go about it. I'd change your function so that it starts off like this. That way, every time it is called, it updates the high, low, and common values.
function calculate() {
var high = document.getElementById('highRi').value;
var low = document.getElementById('lowRi').value;
var common = document.getElementById('comm').value;

Get Titanium.App.Properties in another win or make it global available

Please don’t answer this if you don’t take the time to understand my question or have a reasonable answer. I have got a few answers that is far on the side and I think I explain my problem very clear. Shall this problem drive me nuts or is there somebody out there with a straight and clear answer on Titanium.App.Properties?
I have a login form that stores the username in one:
Titanium.App.Properties.setString("userName",e.value);
and the password in another:
Titanium.App.Properties.setString("passWord",e.value);
The forms TextFields holds these values(after a store) even if I close the window, shut down and restarts the app. This because of the App.Properties.getString("value"); I suppose….?!
But when I copy the hole form with its App.Properties.getString("value"); to another window, the TextFields are empty and contains no value at all. I understand that the Properties string must be there some where in App.Properties, but how can grab it and use it another place in the app?
My question is: How to get the value from my
var userNameValue = Titanium.App.Properties.getString("userNameValue");
to be available in another window or for the hole app(global)? How can I grab it and make use of it a another place in the app? I don’t see a good reason to make these, only separate words, into objects(JSON) since the userName only contains a e-mail address and the passWord consist only of continuing letters or numbers. But if you mean I have too, -how do I set this from my TextField and get it in another TextField somewhere else in my app. I have not had any luck so far. I hope you can help me out and I can keep sane.
Titanium.App.Properties.getString("userNameValue");
This is globally Available, any Propertie of the Titanium Object is accessible in each file.
but if for some reason this doesnt work for you and you want to set a global variable,
you could do the following:
Create a file called myGlobals.js //or anything else,
//Put this in there e.g
var myProperties = {};
in any file you want to use it write in the first line
Ti.include('myGlobals.js');
Then you can make a propertie global available, for example write this in app.js somewhere where the app initializes
myProperties.Username = Titanium.App.Properties.getString("userName");
Then you can get the value in each file by accesing the propertie
myProperties.Username
//of course the Propertie has to be set before you can get them
( Titanium.App.Properties.setString("userName",e.value); ) //like you do it
But, Titanium.App.Properties.getString("userName");
should be avilable from any file anyway, (but you can give this a try although i dont think its nice to do it like this)
i had a similar problem where this didnt get any value from a propertie set in the ios settings as default value.
I had to go to the settings and manually change or edit the default value and then after a restart
Titanium.App.Properties.getString("userName");
returned the value as it should,
i hope this helps you =)
Answer to the Comment
I'm glad i could help you =)
Yes you can Use an focus EventHandler like this :
textfield.addEventListener("focus",function(){
textfield.value = "Test";
});
Beside that , are you using the identical Textfield for both windows ? like
var Textfield = Ti.Ui.createTextField({...});
and add it to 2 different windows ?
win1.add(Textfield);
win2.add(Textfield);
That led for me to Problems with labels in TableViewRows, using an identical Row 2 times in the TableView
The Text displayed only on 1 Label, sometimes it switched the Labels
I think you can't add one and the same titanium object to more then one other object
Maybe that could be the culprit,
dunno just an idea =)

Categories