I'm trying to code a web application and I have encountered a slight issue.
In the top part of the code there is a moving item around the screen. I called that item to randomly move around the screen in the beginning of my code. But then when I click a button its suppose to stop. So what I did was I created a function for when it's clicked, and it captures the x,y,z into a local variable in the function. I then entered these fixed x,y,z values into the item so it remains stationary, but for some reason I think its being overwritten by the top code and still keeps on moving. Is there any way to skip a line of code in the top section of a code when a specific function is made to run?
Code I'm talking about
function motionUpdate()
{
xvalues= //huge code which is obtained from device sensors
yvalues= //huge code which is obtained from device sensors
zvalues= //huge code which is obtained from device sensors
//There are two objects that move id1 and id2. When clicking on button id2 should stop
ui.elememenTranslate(xvalues,yvalues,zvalues,"id1") //moves according to x,y,z location
ui.elememenTranslate(xvalues,yvalues,zvalues,"id2")
}
self.Click = function()
{
var localX = xvalues;
var localY = yvalues;
var localZ = yvalues;
ui.elememenTranslate(xvalues,yvalues,zvalues,"id2")
}
Use a global variable as a condition for the code to run. Example:
var run_code = true;
Then in the code:
function motionUpdate()
{
if(run_code) // if run_code is true, else skip this part
{
....
}
}
In other part of code under certain condition, set as required:
run_code = false;
Once set, above code will be skipped.
Expanding on Ashad Shanto's comment, you can use a flag to save if the button has been clicked.
// Save if the button was clicked
var id2IsStopped = false;
function motionUpdate(){
...
ui.elememenTranslate(xvalues,yvalues,zvalues,"id1") //moves according to x,y,z location
// Don't run translate if the button was clicked
if(!id2IsStopped){
ui.elememenTranslate(xvalues,yvalues,zvalues,"id2")
}
}
self.Click = function(){
...
ui.elememenTranslate(xvalues,yvalues,zvalues,"id2");
// Record that the button was clicked
id2IsStopped = true;
}
This will record the clicked button and stop running the translation on id2. However, if you want to toggle id2's movement, you just need to toggle the value of the flag:
// Previously: id2IsStopped = true;
id2IsStopped = !id2IsStopped;
Related
For a radar chart, I'm trying to toggle (with a switch button) or slide (with a slider) between different sets of data to display. (I'll include the button here first, but I'm eventually try to extend that to a slider later.). 1. Initialize button and keep track of user toggle. 2. Pick which data set to use. both generateRadarData and generateRadarData2 work well on their own if I use chart.data = either one.
The below is the edited attempt:
var chartSwitchButton = chart.chartContainer.createChild(am4core.SwitchButton);
chartSwitchButton.events.on("toggle", function () {chart.data = whichData();})
function whichData() {
var dataToUse = chart.data;
if (chartSwitchButton.isActive) {dataToUse = generateRadarData();
} else {
dataToUse = generateRadarData2();}
return dataToUse};
chart.data = whichData();
I have tried commenting out the last line (since ideally it would have been updated via the event listener), but then no data displays.
Here is a more recent attempt to update the data using invalidateRawData:
chartSwitchButton.events.on("toggle", function (event) {
chart.data = whichData();
chart.invalidateRawData();
});
function whichData() {
var data = [];
if (chartSwitchButton.isActive) {
chart.data = generateRadarData();
} else {
chart.data = generateRadarData2();
}
chart.invalidateRawData(); //also tried invalidateData. tried this command in event listener as well as here.
data.push(chart.data); //attempt to replace/update raw data
//console.log(chart.data);
return chart.data; //this return line is necessary to output data but theoretically shouldn't be.
}
and have tried implementing the if-else w/in the event listener without having to use whichData as a separate function like so:
chartSwitchButton.events.on("toggle", function () {if (chartSwitchButton.isActive) {
chart.data = generateRadarData();
} else {
chart.data = generateRadarData2();
}
chart.invalidateRawData();})
I'm still unable to switch between the two sets of data with user interaction. In fact, if I don't return something for chart.data or declare what chart.data is supposed to be outside of the events.on or whichData(), then none of my data prints at all.
If anybody has suggestions on how to do this with a button (or a slider would be even better) that would be awesome.
Basically, after setting up the button, I tried to (a) keep track of the state of the button (as determined by user), (b) determine which state the button is in, and (c) pick a data set to use based off of that info. This version is edited from a previous attempt as per initial comments below. Thanks for your help.
Documentation is "toggled" not "toggle" in the events listener. The event does not recognize "toggle" but needed "toggled". https://www.amcharts.com/docs/v4/reference/switchbutton/#toggled_event
I have a date input in my page, which I'm using Daterangepicker framework to populate it.
Here is the code of how I start my page!
$(function(){
startSelectors();
var variaveis = returnInputVars();
var rede = variaveis[0];
var codLoja = variaveis[1];
var period = variaveis[2];
console.log('1.'+rede+' 2.'+codLoja+' 3.'+period);
});
function returnInputVars(){
var rede = $("#dropdown-parceria").val();
var codLoja = $("#dropdown-loja").val();
var periodo = $("#datepicker-range").val();
return [rede, codLoja, periodo];
};
The function startSelectors() is set to start my datepicker and other fields, which is working perfectly. After it, I create a var called "variaveis" to fill
with the values of each field because I will use then later (this functions also works perfectly at other scripts of my page).
Running the page, my console returns this:
The funny thing is, if I type at the console this, the value is shown, just while starting the script is does not work!
Anybody experienced something like this?
***UPDATE
Adding this script to my start function:
console.log($("#datepicker-range"));
The value is shown, but the second console.log don't:
EDIT 1. FIDDLE (Suggested by #halleron)
To ensure things are loaded in the correct order, it is useful to apply a page sniffer code snippet that will scan the page continuously until a condition is met, or until a preset counter limit is reached (to prevent strain on browser memory). Below is an example of what I typically use that would fit your scenario.
I think because you are dealing with asynchronous loading, you can't have a global variable that holds the values in a global scope without an interval to detect when it can be used. Otherwise, it will attempt to read the variable when it is not yet ready.
You can invoke functions anywhere you like. But I would keep all of your variables contained within the page_sniffer_2017() because that is a controlled environment where you know that everything successfully loaded and you know that the variables are ready to be accessed without error.
That way, regardless of connection speed, your functions will only fire when ready and your code will flow, sequentially, in the right order.
Within the ajax success options, always add a class to the body of the document that you can search on to determine if it has finished loading.
$(document).ready(function() {
page_sniffer_2017();
});
function page_sniffer_2017() {
var counter = 0;
var imgScanner = setInterval(function() {
if ($("#datepicker-range").length > 0 && $("#datepicker-range").val().length && jQuery('body').hasClass('date-picker-successfully-generated')) {
var periodoDatepicker = $("#datepicker-range").val(); // ok
console.log(periodoDatepicker); // ok
var variaveis = returnInputVars(replaceDate(periodoDatepicker)); // ok
console.log(variaveis[0], variaveis[1], variaveis[2]);
//startNewSelectors(variaveis);
// start ajax call
generateData(variaveis[0], variaveis[1], variaveis[2]);
clearInterval(imgScanner);
} else {
//var doNothing = "";
counter++;
if (counter === 100) {
console.log(counter);
clearInterval(imgScanner);
}
}
}, 50);
}
I am trying to achieve an effect like this on mobile (ios + android):
http://i.imgur.com/6zaTdRd.png
Where the currently selected textfield has a blue tinted icon + underlining
So my framework lacks any support for grey scaling a bitmap image of any sort so I need to swap between two images to achieve this effect.
My current implementation looks like this:
Please note this for the Titanium Alloy MVC framework but I'm guessing the basic logic should be similar.
I listen for blur/focus events to toggle current image
$.firstNameField.addEventListener('focus', function(e){
swapImages($.firstNameField.getParent());
});
$.lastNameField.addEventListener('focus', function(e){
swapImages($.lastNameField.getParent());
});
and then I swap images like so:
/**
* Swaps between the images (..._0 and ..._1) of an ImageView nested in a
TableRow
* ..._0 Greyscale image
* ..._0 Colour image
* #param e current TableViewRow
*/
function swapImages(e){
var imagePathSplit = (e.children[0].image).split('_');
var newImagePath = null;
if(imagePathSplit[1] == "0.png")
newImagePath = imagePathSplit[0] + "_1.png";
else
newImagePath = imagePathSplit[0] + "_0.png";
e.children[0].image = newImagePath;
return;
}
This doesn't look that great especially since I need a lot more fields with this functionality, I also want to implement tabbing (using Return key = NEXT) between the fields which will further balloon to increase 1 more event listener per field.
How would something like this be done ideally? I can think of one way of just creating the fields in code in array form which should help simplify matters (no more looking too far for Parent/Children, but that would still end up using quite a bit of listeners for switching right?
EDIT: Forgot to add how I have the textFields setup:
<TableView id="paypalTable">
<TableViewSection>
<TableViewRow id="firstNameView" class="tableRow">
<ImageView id="firstNameIcon" class="textFieldIcon"/>
<TextField id="firstNameField" class="textField"/>
</TableViewRow>
I tried something similar in one of my projects. Although I had an Alloy project I had to use a classic approach to get my desired behaviour.
In my controller:
var textFields = [];
var yourTextFieldsArray = [];
for (var i = 0; i < yourTextFieldsArray; i++) {
//Set the selected state to false initially. Maybe you need another command for it.
textFieldIsSelected[i] = false;
//create your new view
textFields[i] = Ti.UI.createView({
top : topValues[i],
width : Titanium.UI.FILL,
height : height,
id : i + 1,
touchEnabled : true
});
textFields[i].addEventListener('click', function(e) {
//Check the source id
if (e.source.id - 1 > -1) {
//use your function swapImages(e.source.id). Notice the slightly different parameter since you do not need the complete event.
swapImages(e.source.id);
}
}
function swapImages(id){
//Check the the path variable as you did
var imagePathSplit = (textFields[i-1].image).split('_');
var newImagePath = null;
if(imagePathSplit[1] == "0.png")
newImagePath = imagePathSplit[0] + "_1.png";
else
newImagePath = imagePathSplit[0] + "_0.png";
textFields[i-1].image = newImagePath;
}
This approach lets you use the same event listener for every property.
Please notice that my ids start at 1 and not at 0. This is because I had to implement such a behaviour for images and ImageViews do not accept id=0. My guess is that TextViews don't do it either so you should stick with it. Further notice that you need to decrement the id to get the corresponding object in the textFields Array. Otherwise you would get an out of bounds error.
You should create one more event listener for your NEXT event. Implement it in the same way as the first eventListener. Maybe the code is not perfect because I wrote it from my memory. If there are any questions left feel free to ask in the comments.
I am attempting to show a certain class if a user clicked the right answer or wrong answer through the {{checkAnswer}} helper below:
<div class="question" {{attributes}}>
A
{{answerOne}}
</div>
A user submits an answer which creates a submission, and then ultimately that user submission is checked to see if it is correct. If the user submission is correct it should display btn-success, incorrect should be btn-danger, and else should be btn-primary.
Template.questionItem.helpers({
checkAnswer: function() {
var user = Meteor.user();
var game = GameCollection.findOne({current: true});
var currentQuestion = game.currentQuestion;
var question = game.gameQuestions[currentQuestion];
var correctAnswer = question.correctAnswer;
var submission = Submissions.findOne({userId: user._id,
gameId: game && game._id,
currentQuestion: currentQuestion});
if (submission && submission.submission === correctAnswer) {
return 'btn-success';
} else if (submission) {
return 'btn-danger';
} else {
return 'btn-primary upvotable'
}
},
When I click a correct submission it turns green from btn-success for a fraction of a second (and if incorrect it turns red for a fraction of a second) but then ultimately goes to btn primary. Why does it not stay btn-success (or btn-danger)?
Something in the context is changing. Meteor data contexts are built in such a way that all the 'current' checking you're doing isn't necessary. You can instead access the current data context using this, which will significantly simplify your code.
I'd start by checking if the submission is correct or not on the server side, and then storing that as a property of the submission itself. Then, you can do a simple if...then to return the correct bootstrap class name.
Here's a simple example: meteorpad
And if you want the JS files to quickly put into a brand new project, here's a Gist.
You'll notice in both of those how you can use this._id or this.correct to access the correct/current data context. Hope that helps / gets you on the right track.
So i have the global variable
var INSIDE_GLOBAL = {} ;
INSIDE_GLOBAL.current_search = get_new_current_search();
function get_new_current_search() {
return {
stack:[],
search_options: {
keywords: ""
},
};
}
Then, I setup handlers for clicking different div sections in an accordion. This adds a new section to the accordion, makes it the currently viewed section, and sets up the click handlers for the next sections with the same function (setup_search_click_handlers).
function setup_search_click_handlers() {
$('.search_option').unbind("click");
$('.search_option').bind("click", function(e) {
var new_sub_group = $(this).attr('id');
$("#new_search_panel").bind("accordionchange", function(event, ui) {
$("#new_search_panel").unbind("accordionchange");
//push new section onto the current searches
INSIDE_GLOBAL.current_search.stack.push(new_sub_group);
/* pseudo code */
accordion_add_section_and_select_that_section( with_callback: setup_search_click_handlers );
});
$("#new_search_panel").accordion("activate",-1); //Collapse the accordion, calls the newly binded change
});
}
At the end of the first click, INSIDE_GLOBAL.current_search.stack has an element in it;
However, when the next click event happens and the binded function called, INSIDE_GLOBAL.current_search.stack is back to being empty. Can't figure out why.
I'm assuming it has something todo with the scope of the different call backs, but really not sure.
In firebug, I can see the Window INSIDE_GLOBAL changing correctly, then being "reset" to where the stack array is empty again
Just figured it out. Makes sense that I would spend hours trying to figure out the issue, then find it moments after posting here.
I had just added the stack array to my code and changed over some indexes being passed around in methods to just using the stack.length field.
I have a binding elsewhere that calls a function whenever a the accordion minimizes. This is used when the person clicks a previous section in the accordion (going backwards in the search). It checks a few parameters to make sure this is the case and removes the sections of the accordion after the one the user clicked. while doing this it also calls stack.pop() in order to keep the backend data up to date.
By changing from using index variables to the length variable, the first time the accordion minimized, this check would incorrectly pass and pop the just variable to the stack...
Here's part of the code for whoever was curious
function setup_return_to_previous_handlers() {
var event_function = function(event, ui) {
var active_index = $("#new_search_panel").accordion( "option", "active" );
var index = INSIDE_GLOBAL.current_search.stack.length; //BUG here: needs to be length-1;
//alert("accord_change: active:"+active_index+" index:"+index);
if ( typeof active_index==="number" && //Filter's active === false, if user clicked last section
active_index >= 0 && //Filters refreshes
active_index != index ) { //User clicked previous section
$("#new_search_panel").unbind("accordionchange");
bind_search_buttons();
//alert("inside");
for ( ; index > active_index; --index) {
/* remove accordion sections */
INSIDE_GLOBAL.current_search.stack.pop(); //Bug: Shouldn't have been called
}
}
};
$("#new_search_panel").unbind("accordionchange");
$("#new_search_panel").bind("accordionchange", event_function);
}