Pass a new argument in Javascript code to target HTML5 attr - javascript

I currently have created a piece of Javascript code which checks a http response and if its a successful 200 code the traffic light shows green and if its not a 200 code the traffic light flashes red.
My current problem at the moment is I want to be able to pass Two arguments to the initializing function like so
requestResponses.init('/status', "ATTR");
The first attribute being the URL I want to test against and the second attribute being the value of the HTML5 data-request attribute I have created.
My reason for this as I want to have multiple traffic lights on the same page targeting different URL's simultaneously without effecting each other.
So for Example I create a data request attribute and give it a value of Four I then want to be able to hook it up like so
requestResponses.init('/status', "Four");
and start targeting elements like below within the code. This makes it that bit more modular and reusable.
.cp_trafficLight[data-request="Four"]
Please find my code attached and a working JSFiddle.
var requestResponses = {
greenLight: $('.cp_trafficLight_Light--greenDimmed'),
redLight: $('.cp_trafficLight_Light--redDimmed'),
greenBright: 'cp_trafficLight_Light--greenBright',
redBright: 'cp_trafficLight_Light--redBright',
settings: {
flashError: 400,
requestTime: 10000
},
init: function (url, targAttr) {
requestResponses.url = url;
requestResponses.getResponse(requestResponses.url, targAttr);
setInterval(function () {
if (requestResponses.errorCode === true) {
requestResponses.redLight.toggleClass(requestResponses.redBright);
}
}, requestResponses.settings.flashError);
},
successResponse: function (targAttr) {
requestResponses.errorCode = false;
requestResponses.redLight.removeClass(requestResponses.redBright);
requestResponses.greenLight.addClass(requestResponses.greenBright);
console.log(targAttr);
},
errorResponse: function (targAttr) {
requestResponses.greenLight.removeClass(requestResponses.greenBright);
},
getResponse: function (serverURL, targAttr) {
$.ajax(serverURL, {
success: function () {
requestResponses.errorCode = false;
requestResponses.successResponse(targAttr);
},
error: function () {
requestResponses.errorCode = true;
requestResponses.errorResponse(targAttr);
},
complete: function () {
setTimeout(function () {
requestResponses.getResponse(requestResponses.url);
}, requestResponses.settings.requestTime);
}
});
},
errorCode: false
}
requestResponses.init('/status', "TEST");
https://jsfiddle.net/8700h582/
Appreciate any help!

Then in your function you include a second parameter separated with a comma.
function foo(param1, param2) {
//Do something.
};
foo("1st", "2nd");
EDIT
i see now in your init include the second param for the light and in the init function pass this second param to your request and then from there pass it down to your error and respons function. And then return the function. That can be held in a var.

Related

Parse JSON to create Object in Javascript

Maybe this was already discussed somewhere, I myself could not find an exact answer how to approach my problem:
I have a mutliniear «story» which executes code in each segment. I wrote a state machine, which initiates a new segment, whenever another segment calls that one. Each segment has an onEnter-, an onCheck and an onLeave function. As the name already says, the onEnter executes when the segment is called, the onCheck checks some input until some conditions are fullfilled (if yes they will lead to another segment) and onLeave executes just before the next segment is called.
Currently I just wrote a javascript object kinda like this:
var flow = {
seg1: {
onEnter: function() {
this.say('Seg1');
},
onCheck: function(data) {
if (data.condition) {
machine.callNextSeg('seg2');
} else if (data.condition2) {
machine.callNextSeg('seg3');
}
},
onLeave: function() {
}
},
seg2: {
onEnter: function() {
this.say('Seg2');
},
onGestureCheck: function(data) {
},
onLeave: function() {
}
},
seg3: {
onEnter: function() {
this.say('Seg3');
},
onGestureCheck: function(data) {
},
onLeave: function() {
}
}
};
The example is a bit simplified for understanding, but the code inside would be a little more complex.
I would rather like to have a JSON file, which is loaded, parsed and creates such an object. The JSON File should use a more simple and more abstract syntax to write. Especially to make it quicker.
I imagine something like this:
{
"seg1": {
"onEnter": {
"say": 'Seg1'
},
"onCheck": {
"condition1": "seg2",
"condition2": "seg3"
},
"onLeave": {
}
},
"seg2": {
"onEnter": {
"say": 'Seg2'
},
"onCheck": {
},
"onLeave": {
}
}
}
The conditions are booleans and if true the described segment should be called.
Would that be easy to parse the json, create an object, and create functions inside it for each onEnter, onCheck and onLeave? And also write the necessary if clauses?
Thanks for hints into the right direction.
cheers
J.
var flow = {...} is an object literal and is actually best suited for what you need to do, but I do understand the desire to have all of this "defined" in a JSON file. The issue there becomes the fact that the application processing your JSON file MUST understand/be Javascript (which defies the idea of having JSON as language agnostic - its name notwithstanding).
This might be what you need:
JavaScript Function Serialization
Also check the voted answer here:
What is the correct way to "serialize" functions in javascript for later use

Javascript: Call a method inside another method

I have a simple app, that triggers a boolean and sets a task to completed:
But I want to be able use a "Complete All" Button and set every task to complete. This here works fine:
completeAll: function() {
this.tasks.forEach(function(task) {
task.completed = true;
});
},
http://codepen.io/anon/pen/avzMYr
But instead of setting it directly, I would like to use a method that is called like this, because I have a lot of other code that needs to be separated.
completeTask: function(task) {
task.completed = true;
},
completeAll: function() {
this.tasks.forEach(function(task) {
this.completeTask(task);
});
},
Yet this does not work, see here:
http://codepen.io/anon/pen/EVaMLJ
Any idea how to call the "completeTask(task)" method inside of the completeAll method?
Your problem is that the value of this inside the .forEach() callback is not the same as what it is outside. You can save the outer value of this and then use that saved version to get what you want:
completeAll: function() {
var self = this;
this.tasks.forEach(function(task) {
self.completeTask(task);
});
},
You could use Bind for setting the this value in methods like this:
completeAll: function() {
this.tasks.forEach(function(task) {
this.completeTask(task);
}.bind(this));
}

Properly loading Template.templateName.rendered data context

I have a template, chartEditPreview, that runs a D3.js chart-drawing function once the rendered callback fires. It looks like this:
Template.chartEditPreview.rendered = function() {
drawChart(".chart-container", this.data);
}
Where .chart-container is the target div and this.data is the data for the object in the DB currently being accessed. Problem is, this.data often returns null, seemingly at random. It looks like this has something to do with how the publish/subscribe pattern works — Iron Router (which I'm using) lets the templates render and then hot-pushes the data into those templates.
My question is (hopefully) pretty simple: how can I make sure this.data is actually full of DB data before drawChart is run? Should I be doing this in some other way, instead of calling it on the rendered callback?
I'm thinking of storing the DB data in a Session variable during the routing and calling that from rendered, but it seems like an extra step, and I'm not certain it'll fix this problem. The chart's also not rendered only once on the page — it's interactive, so it needs to be redrawn every time the database object is updated via one of the inputs on screen.
Any help would be much appreciated. Thanks!
For reference, here's what my routes.js looks like:
Router.route('/chart/edit/:_id', {
name: 'chart.edit',
layoutTemplate: 'applicationLayout',
yieldRegions: {
'chartEditType': { to: 'type' },
'chartEditPreview': { to: 'preview' },
'chartEditOutput': { to: 'output' },
'chartEditAside': { to: 'aside' },
'chartEditEmbed': { to: 'embed' }
},
data: function () {
return Charts.findOne({_id: this.params._id});
},
waitOn: function () {
return Meteor.subscribe('chart', this.params._id);
}
});
And my publications.js:
Meteor.publish("chart", function (id) {
return Charts.find({ _id: id });
});
This is a common problem with Meteor. While the subscription might be ready (you should check for it like Ethaan shows) , that does not mean the find() function actually had time to return something.
Usually I solve it with some defensive code, i.e:
Template.chartEditPreview.rendered = function () {
if(this.data)
drawChart(".chart-container", this.data);
// else do nothing until the next deps change
}
Of course this is not as clean as it should be, but as far as I know the only way to solve problems like this properly.
Updated answer
In this case we need a dependency to trigger rerun on data change. Iron router solves this for us:
Template.chartEditPreview.rendered = function () {
var data = Router.current() && Router.current().data();
if(data)
drawChart(".chart-container", data);
// else do nothing until the next deps change
}
add this.ready() into the data:function
data: function () {
if(this.ready()){
return Charts.findOne({_id: this.params._id});
}else{
this.render('loading')
}
},
Something using data and waitOn could be a little bit tricky
Template.chartEditPreview.rendered = function() {
Meteor.setTimeout(function(){
drawChart(".chart-container", this.data);
},1000)
}

OO JavaScript circumventing .call

Take a look at the fiddle here
In the show function the JavaScript call method is used to make this refer to the container variable in my contactForm object. I think, I'm not too sure about the magic that makes this work. Can someone elucidate why this does work, and what a good alternative might be?
JS
$(document).ready(function () {
var contactForm = {
container: $('#contact'),
config: {
effect: 'slideToggle',
speed: 400
},
/*******************/
init: function (config) {
$.extend(this.config, config);
$('<button>').text('Contact me')
.attr('type', 'button')
.insertAfter('#firstArticle')
.on('click', this.show);
//currently only logic on the close button
},
/*******************/
show: function () {
//using variable names to shorten up
var cf = contactForm,
container = cf.container,
config = cf.config;
if (container.is(':hidden')) {
cf.close.call(container);
container[config.effect](config.speed);
}
},
/*******************/
close: function () {
var self = $(this);
if (self.find('span.close').length) {
return;
}
$('<span>').addClass('close')
.text('close')
.prependTo(this)
.on('click', function () {
//self= span
self[contactForm.config.effect](500)
});
}
};
contactForm.init();
});
There's no magic at all; that's just how call works. call lets you call a JavaScript function and manually specify the this value therein, followed by all of the parameters, listed out individually.
So
cf.close.call(container);
calls cf.close with the this value set to container. Hypothetically, this
cf.close.call(container, 1, 'b');
would do the same thing, except also pass in 1 and 'b' as parameters.
Call is very, very similar to apply, with the difference being that apply takes all parameters as an array, rather than being listed out individually. So the (hypothetical) second example would be the same as
cf.close.apply(container, [1, 'b']);
This can be incredibly useful when you want to call another function, set the this value, and wholesale pass all of the current function's arguments along for the ride. Ie
someFunction.apply(thisValue, arguments);

Illegal invocation Error

I only have one function in my scripts page, and it is giving me this error: Uncaught TypeError: Illegal invocation. To be honest, I've never seen this error before, and none of the other cases that I found online seemed to apply to me. My jquery is below, and I don't think any other pieces are necessary, but let me know and I can post other parts.
$(document).ready(function () {
/*----UPDATE BOX REQUEST----*/
$(".boxesChange").live("click", function () {
entry = $(this).closest("tr");
delivered = $(entry).find("#delivered");
if ((delivered).is(":checked")) {
deliveredBoolean = "1";
} else {
deliveredBoolean = "0";
}
boxesDelivered = $(entry).find("#boxesDelivered").val();
bubbleWrapDelivered = $(entry).find("#bubbleWrapDelivered").val();
supplyRequestId = $(entry).find(".boxesSupplyRequestId").val();
$.post('boxesChange.php', {
'delivered': delivered,
'boxesDelivered': boxesDelivered,
'bubbleWrapDelivered': bubbleWrapDelivered,
'supplyRequestId': supplyRequestId
}, function (response) {
$(this).closest(".boxesScheduleEntry").css("background-color", "#ccffcc");
});
return false;
});
});
The problem is in your $.post call. You're trying to set 'delivered' to delivered, which is a jQuery object, I assume you meant deliveredBoolean.
Also, in the callback function this is not what you think it is, it's the jqXHR object, not the element.
var $this = $(this);
$.post(
'boxesChange.php',
{
'delivered': deliveredBoolean,
'boxesDelivered': boxesDelivered,
'bubbleWrapDelivered': bubbleWrapDelivered,
'supplyRequestId': supplyRequestId
},
function (response) {
$this.closest(".boxesScheduleEntry").css("background-color", "#ccffcc");
}
);
I assume the error is inside of this part:
function (response) {
$(this).closest(".boxesScheduleEntry").css("background-color", "#ccffcc");
}
Here I think you want this to be the same as above when you are using closest to get the "tr" element. But in here this is the context of the $.post imho.
You either need to bind or rather do var boxChange = $(this), at the top of the event handler function and use the cached reference afterwards

Categories