Matching and unmatching responsive JavaScript with .matchMedia() - javascript

I am having difficulty getting some responsive js to work. I have 5 breakpoints and the desired outcome is that js functions are matched when the breakpoint is active, and unmatched when the breakpoint is no longer active.
Below is the approach I have taken. The problem I am encountering is with the unmatching, it works going from bp1 -> bp5 but not bp5 -> bp1.
Any help is appreciated
var breakpoints = {
bp1: //.....,
bp2: //.....,
//.....
bp5: //.....
};
var queries = {
bp1: {
match: function() {
console.log('smalltouch portrait');
//...
},
unmatch: function() {
console.log('unmatch smalltouch portrait');
//...
},
active: false
},
bp2: {
match: function() {
console.log('smalltouch landscape');
//...
},
unmatch: function() {
console.log('unmatch smalltouch lanscape');
//...
},
active: false
},
//.....
bp5: {
match: function() {
console.log('standard desktop');
//...
},
unmatch: function() {
console.log('unmatch standard desktop');
//...
},
active: false
}
};
for (var name in breakpoints){
// need to scope variables in a for loop
!function(breakName, query) {
// the callback
function cb(data){
// add class name associated to current breakpoint match
$('body').toggleClass(breakName, data.matches);
//unmatch previous matches
if (data.matches === false && queries[breakName].active) {
queries[breakName].unmatch();
queries[breakName].active = false;
}
//match to breakpoint
if (data.matches === true) {
queries[breakName].match();
queries[breakName].active = true;
}
}
// run the callback on current viewport
cb({
media: query,
matches: matchMedia(query).matches
});
// subscribe to breakpoint changes
matchMedia(query).addListener(cb);
}(name, breakpoints[name]);
}

I believe I figured it out. I've changed the way the unmatch happens
var breakpoints = {
bp1: //.....,
bp2: //.....,
//.....
bp5: //.....
};
var queries = {
bp1: {
match: function() {
console.log('smalltouch portrait');
//...
},
unmatch: function() {
console.log('unmatch smalltouch portrait');
//...
}
},
bp2: {
match: function() {
console.log('smalltouch landscape');
//...
},
unmatch: function() {
console.log('unmatch smalltouch lanscape');
//...
}
},
//.....
bp5: {
match: function() {
console.log('standard desktop');
//...
},
unmatch: function() {
console.log('unmatch standard desktop');
//...
}
}
};
var prevBreakpoint = '';
for (var name in breakpoints){
// need to scope variables in a for loop
!function(breakName, query) {
// the callback
function cb(data){
// add class name associated to current breakpoint match
$('body').toggleClass(breakName, data.matches);
if (data.matches === true) {
if (prevBreakpoint) {
queries[prevBreakpoint].unmatch();
}
queries[breakName].match();
prevBreakpoint = breakName;
}
}
// run the callback on current viewport
cb({
media: query,
matches: matchMedia(query).matches
});
// subscribe to breakpoint changes
matchMedia(query).addListener(cb);
}(name, breakpoints[name]);
}

Related

Argument is returning empty value on console.log

I am trying to pass an argument down the tree to the successResponse errorResponse functions and display the value in the console before I do any work with it.
Currently I am getting an empty value in the console so there must be something missing in my code. I am thinking its a return statement but when I attempt this I get no result.
Any help would be greatly appreciated.
The console.log is below.
successResponse: function (getSel) {
requestResponses.errorCode = false;
requestResponses.redLight.removeClass(requestResponses.redBright);
requestResponses.greenLight.addClass(requestResponses.greenBright);
console.log(getSel);
},
Here is the full version of my code
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, getSel) {
requestResponses.url = url;
requestResponses.getResponse(requestResponses.url, getSel);
setInterval(function () {
if (requestResponses.errorCode === true) {
requestResponses.redLight.toggleClass(requestResponses.redBright);
}
}, requestResponses.settings.flashError);
},
successResponse: function (getSel) {
requestResponses.errorCode = false;
requestResponses.redLight.removeClass(requestResponses.redBright);
requestResponses.greenLight.addClass(requestResponses.greenBright);
console.log(getSel);
},
errorResponse: function () {
requestResponses.greenLight.removeClass(requestResponses.greenBright);
},
getResponse: function (serverURL, getSel) {
$.ajax(serverURL, {
success: function (getSel) {
requestResponses.errorCode = false;
requestResponses.successResponse(getSel);
},
error: function () {
requestResponses.errorCode = true;
requestResponses.errorResponse();
},
complete: function () {
setTimeout(function () {
requestResponses.getResponse(requestResponses.url);
}, requestResponses.settings.requestTime);
}
});
},
errorCode: false
}
requestResponses.init('/status');
Appreciate any help.
Your code looks fine. Make sure that the server actually responds with data. The problem is most likely on back-end.

Javascript functions in custom namespaces

It is possible to declare 2 more functions in main function like this ?
var jquery4u = {
init: function() {
jquery4u.countdown.show();
},
countdown: function() {
show: function() {
console.log('show');
},
hide: function() {
console.log('hide');
}
}
}
jquery4u.init();
and i receive the following error: Uncaught SyntaxError: Unexpected token ( on this line "show: function() {"
Remove the function from the right of the countdown (demo)
var jquery4u = {
init: function() {
jquery4u.countdown.show();
},
countdown: {
show: function() {
console.log('show');
},
hide: function() {
console.log('hide');
}
}
}
jquery4u.init();
Next time, use jsFiddle to make a demo and click the "JSHint" button.
Actually, none of this will work. Unless you make countdown an object or you treat its sub-functions as proper functions.
Why: Under countdown, you created an instance of object not a function.
var jquery4u = {
countdown: function() {
show = function() {
console.log('show');
}
hide = function() {
console.log('hide');
}
jquery4u.countdown.show();
}
}
The above code is a valid code so it is possible. Unfortunately it will not return anything.
The proper way to do this is in this format:
var jquery4u = {
countdown: {
show: function() {
console.log('show');
},
hide: function() {
console.log('hide');
}
}
}
This will work. You can try it out by calling:
jquery4u.countdown.show();

Do something once, then every 15 seconds in react js

I have the following code:
var Panel = React.createClass({
getInitialState: function () {
return {
user_id: null,
blogs: null,
error: false,
error_code: '',
error_code: ''
};
},
shouldComponentUpdate: function(nextProps, nextState) {
if (nextState.error !== this.state.error ||
nextState.blogs !== this.state.blogs ||
nextState.error_code !== this.state.error_code
) {
return true;
}
},
componentDidMount: function() {
var self = this;
var pollingInterval = setInterval(function() {
$.get(self.props.source, function(result) {
if (self.isMounted()) {
self.setState({
error: false,
error_code: '',
error_message: '',
blogs: result.user.blogs,
user_id: result.user.id
});
}
}.bind(self)).fail(function(response) {
self.setState({
error: true,
error_code: response.status,
error_message: response.statusText
});
}.bind(self));
}, 1000);
},
render: function() { ... }
});
The important part to focus on is the componentDidMount This will fetch every second, regardless if there is an error or not. The render function, assuming theres an error, will display the appropriate method. So for all intense and purpose, this code does exactly what I want it to do, it fetches, if it fails, it fetches again until it succeeds.
But I need to make some changes, and this is where I am lost. I want to say: Fetch once, pass or fail - it doesn't matter. THEN every 15 seconds after that initial fetch, try again - regardless of pass or fail
I would normally spin up a backbone collection and router along with a poll helper to do all this, but in this specific case there is no need for the extra overhead. So thats where I am stumped. How do I accomplish what I am trying to achieve?
You should be able to just refactor your code a bit to be able to call your polling function a few different ways (like manually for example and then at a specified interval):
componentDidMount: function() {
this.startPolling();
},
componentWillUnmount: function() {
if (this._timer) {
clearInterval(this._timer);
this._timer = null;
}
},
startPolling: function() {
var self = this;
setTimeout(function() {
if (!self.isMounted()) { return; } // abandon
self.poll(); // do it once and then start it up ...
self._timer = setInterval(self.poll.bind(self), 15000);
}, 1000);
},
poll: function() {
var self = this;
$.get(self.props.source, function(result) {
if (self.isMounted()) {
self.setState({
error: false,
error_code: '',
error_message: '',
blogs: result.user.blogs,
user_id: result.user.id
});
}
}).fail(function(response) {
self.setState({
error: true,
error_code: response.status,
error_message: response.statusText
});
});
}

module pattern and document.ready

I have started learning the javascript module pattern and I have the following code:
// PersonalInformation.js
var PersonallInformation = (function () {
$.validator.addMethod("checkPhoneNumber", function (value, element) {
if (!value) return true;
return /^((\+7)|8)(700|701|702|705|707|712|713|717|718,721|725|726|727|777)[0-9]{7}$/.test(value);
}, "Wrong phone format");
function updateQTip() {
$('div.invalid_form').qtip({
content: function (api) {
var text = $(this).prev();
return "<div class='tip_cont'><span class='simple cost'><span class='corner'></span>" + $(text).attr('data-description') + "</span></div>";
},
position: {
target: 'mouse',
adjust: { x: 5, y: 17 }
},
style: {
tip: { corner: false }
}
});
}
function updateError() {
$('.invalid_form').closest('.wrap_input').addClass('error');
$('#reg_form_pay input').each(function(element) {
if ($(this).hasClass('invalid_form')) {
$(this).closest('.wrap_input').addClass('error');
} else {
$(this).closest('.wrap_input').removeClass('error');
}
});
updateQTip();
}
function validateForm() {
$("#reg_form_pay").validate({
rules: {
Email: { required: true, email: true },
PhoneNumber: { required: true, checkPhoneNumber: true },
FirstName: { required: true },
Surname: { required: true }
},
messages: {
Email: '',
PhoneNumber: '',
FirstName: '',
Surname: ''
},
errorClass: "invalid_form",
errorElement: "div",
errorPlacement: function (error, element) {
error.insertAfter(element);
},
onkeyup: false,
showErrors: function (errorMap, errorList) {
this.defaultShowErrors();
updateError();
}
});
}
function privateInit() {
validateForm();
console.log('init ok');
}
return {
init: privateInit,
};
}());
To make this code work I have to call the init method in the view as follows:
<script>
$(document).ready(function() {
PersonallInformation.init();
})
</script>
Is it possible to avoid having to call init in the view?
UPDATE:
I have rewritten it in the following way:
function library(module) {
$(function() {
if (module.init) {
module.init();
}
});
return module;
}
var PersonallInformation = library(function () {
...
The short answer is no
your validateForm method uses the DOM to do it's work. If you call the init method prior to document.ready the behavior is unspecified.
You will have to call some method in document.ready.
You are not really using the module partern since you are in effect just encapsulating function in another function so you would have the same kind of encapsulation if you moved the entire code between (function (){...}()) to document.ready in which case you could change the last part of the function to
validateForm();
console.log('init ok');
Ie inline the init function.
EDIT
A rewrite could be something like:
var setupValidate = (function () {
return function(options) {
var defaultOptions = {
qtipOptions : {
content: function (api) {
var text = $(this).prev();
return "<div class='tip_cont'><span class='simple cost'><span class='corner'></span>" + $(text).attr('data-description') + "</span></div>";
},
position: {
target: 'mouse',
adjust: { x: 5, y: 17 }
},
style: {
tip: { corner: false }
}
},
formSelector : "#reg_form_pay",
invalidFormSelector : 'div.invalid_form',
};
options = $.extend(defaultOptions,options);
$.validator.addMethod("checkPhoneNumber", function (value, element) {
if (!value) return true;
return /^((\+7)|8)(700|701|702|705|707|712|713|717|718,721|725|726|727|777)[0-9]{7}$/.test(value);
}, "Wrong phone format");
function updateQTip() {
$(options.invalidFormSelector).qtip();
}
function updateError() {
$(options.invalidFormSelector).closest('.wrap_input').addClass('error');
$(options.formSelector).find("input").each(function(element) {
if ($(this).hasClass('invalid_form')) {
$(this).closest('.wrap_input').addClass('error');
} else {
$(this).closest('.wrap_input').removeClass('error');
}
});
updateQTip();
}
function validateForm() {
$(formSelector).validate({...});
}
validateForm();
console.log('init ok');
}
}());
and you'd then call it like:
$(function(){
setupValidate (/*with options if you'd like to change the default*/);
});

Load method of Ext.data.store - how to delay a return statement AND a function call until the data is loaded?

connectLoadRenderStoreAndGetCheckBox: function () {
this.someStore = new Ext.data.Store({
proxy:
reader:
]),
sortInfo: { field: , direction: }
});
this.someStore.load(
{
params:
{
}
});
//I left out parameters; lets assume they are valid and work.
this.someStore.on("load", this._renderColumns, this);
return ([this._getCheckBox()]);
}
On 'load' I want to both execute the function this._renderColumns (which uses the data from the server) and also return a checkbox (which also uses data from the server).
What is a quick & easy way to only return the checkbox after the data is loaded?
_getCheckBox: function () {
if (UseDefault == "y") {
return new Ext.form.Checkbox(
{
fieldLabel:,
itemCls:,
checked: true,
labelStyle:
});
}
else {
return new Ext.form.Checkbox(
{
fieldLabel:,
itemCls:,
checked: false,
labelStyle:
});
}
},
_renderColumns: function () {
var record2 = this.something.something2(2);
UseDefault = record2.get("UseDefault");
}

Categories

Resources