Skip to content

Instantly share code, notes, and snippets.

@jcottrell
Created June 15, 2016 16:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jcottrell/2cd37c0016d3d35e2e9db0f39344cf8a to your computer and use it in GitHub Desktop.
Save jcottrell/2cd37c0016d3d35e2e9db0f39344cf8a to your computer and use it in GitHub Desktop.
Functional Friend Messenger
<div class="container wrap">
<header>Functional Friend Messenger</header>
<section>
<form class="form">
<div class="form-group">
<input class="form-control" type="text" name="message" placeholder="Message" />
</div>
<div class="form-group">
<div class="checkbox-inline">
<label for="teens">
<input class="checkbox" type="checkbox" name="filters[]" id="teens" value="teens" />Teens
</label>
</div>
<div class="checkbox-inline">
<label for="oddAges">
<input class="checkbox" type="checkbox" name="filters[]" id="oddAges" value="oddAges" />Odd Ages
</label>
</div>
<div class="checkbox-inline">
<label for="programmers">
<input class="checkbox" type="checkbox" name="filters[]" id="programmers" value="programmers" />Programmers
</label>
</div>
<input class="btn btn-primary" style="margin-left:15px;" type="submit" value="Send" />
</div>
</form>
</section>
</div>
/*=== Suggested JS window width for readability (this is one line) ===*/
// data - example friends
let friends = [
{name: 'Joe', age: 11, job: 'programmer'},
{name: 'Ali', age: 14, job: 'student'},
{name: 'Jil', age: 15, job: 'programmer'},
{name: 'Art', age: 16, job: 'student'},
{name: 'Phi', age: 36, job: 'manager'},
{name: 'Pat', age: 55, job: 'programmer'}
];
// Mini-dom functions
// Curry a generic element by attribute getter
let getElementsByAttribute = R.curry(function (attr, val) {
return Array.prototype.slice.call(
document.querySelectorAll('['+attr+'="'+val+'"]')
);
});
// partially apply for different element types (name and type)
let getElementsByName = getElementsByAttribute('name');
let getElementsByType = getElementsByAttribute('type');
// element value getters
let getTextValue = el => el.value;
let getCheckboxChecked = el => ({name:el.value, checked:el.checked});
// Curry a generic value getter
let getInputValues = R.curry(function (typ, els) {
return els.map(el => typ(el));
});
// partially apply to use different value getters
let getTextInputValues = getInputValues(getTextValue);
let getCheckboxInputValues = getInputValues(getCheckboxChecked);
// View stuff
// Get dom elements
let messageBox = getElementsByName('message');
let filterBoxes = getElementsByName('filters[]');
let submitButton = getElementsByType('submit').pop();
// Get info from dom elements
let getMessage = function () {
return getTextInputValues(messageBox).pop();
};
let getFilters = function () {
return getCheckboxInputValues(filterBoxes).
reduce(function (filters, box) {
if (box.checked) {
if (box.name === 'teens') {
filters.push(isTeenFriend);
} else if (box.name === 'oddAges') {
filters.push(isOddAgeFriend);
} else if (box.name === 'programmers') {
filters.push(isProgrammerFriend);
}
}
return filters;
}, []);
};
// Attach dom listener for form
document.querySelector('form').addEventListener('submit',
function (e) {
e.preventDefault();
shareFriends(getMessage());
}
);
// Program logic
// Potential filters
// Number filters
// isNumber -> Number.isInteger
let isTeen = num => num >= 13 && num <= 19;
let isOdd = num => num % 2 === 1;
// Programmer filter
let isProgrammer = job => job === 'programmer';
// Curry and then partially apply to get filters for friends
let validAttribute = R.curry((attr, tester, friend) => tester(friend[attr]));
let validAgeFilter = validAttribute('age');
let isTeenFriend = validAgeFilter(isTeen);
let isOddAgeFriend = validAgeFilter(isOdd);
let isProgrammerFriend = validAttribute('job', isProgrammer);
// Curry a composer of filters
let validFriendByAllFilters = R.curry(function (filters, friend) {
return R.allPass(filters)(friend);
});
// Curry a share function
let share = R.curry(function (friends, message) {
// partially apply to get an array of filters to run friends through
var filters = validFriendByAllFilters(getFilters());
// do the filtering and send the message
friends.filter(filters).
forEach(function (friend) {
console.log(friend.name + ': ' + message);
});
console.log(help);
});
// partially apply the share function (could be more groups in the future?)
let shareFriends = share(friends);
// debug and testing
let help = '--Call showFriends() in the console to see friend data--';
function showFriends() {
friends.forEach(function (friend) {
console.log(JSON.stringify(friend));
});
return help;
};
console.log(help);
<script src="//cdn.jsdelivr.net/ramda/latest/ramda.min.js"></script>
.container.wrap {
width:80%;
}
.container header {
font-weight:bold;
font-size: 24px;
}
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment