miguelslp - Vanilla JS

Places - Filter

Explore cool, quirky places in your own backyard.

Filter:
Loading...
<p>Explore cool, quirky places in your own backyard.</p>

<div class="filters">
<strong>Filter:</strong>
<label>
<input type="radio" name="view" value="all" checked />
All Places
</label>

<label>
<input type="radio" name="view" value="faves" />
Favorites
</label>

<label>
<input type="radio" name="view" value="visited" />
Visited
</label>

<label>
<input type="radio" name="view" value="not-visited" />
Not Visited
</label>
</div>

<div id="app">Loading...</div>

<script src="../../node_modules/reefjs/dist/reef.min.js"></script>
<script>
// Get place data from the API and update app state
var getPlaces = function () {
fetch("https://vanillajsacademy.com/api/places.json")
.then(function (response) {
if (response.ok) {
return response.json();
}
return Promise.reject(response);
})
.then(function (data) {
app.data.faves = getFromStorage(favesID);
app.data.visited = getFromStorage(visitedID);
app.data.filter = "all";
app.data.places = data;
})
.catch(function (err) {
console.warn(err);
app.data.places = null;
});
};

// The app component
var app = new Reef("#app", {
data: {},
template: function (data) {
// If there are places, render them
if (data.places && data.places.length) {
return getPlacesHTML(data);
}

// Otherwise, show an error
return getNoPlacesHTML();
},
});

// Get the message to dispay if there is no palce data
var getNoPlacesHTML = function () {
return `<p><em>Unable to find any places right now. Please try again later. Sorry!</em></p>`;
};

// Create HTML for each of the palces from the app data
var getPlacesHTML = function (props) {
return props.places
.map(function (place) {
var html =
'<div class="place' +
" " +
getHidden(place, props) +
'"' +
">" +
"<div>" +
'<img alt="" src="' +
place.img +
'">' +
"</div>" +
"<div>" +
"<h2>" +
place.place +
"</h2>" +
"<p>" +
place.description +
"</p>" +
"<p><em>" +
place.location +
'</em><br><a href="' +
place.url +
'">' +
place.url +
"</a></p>" +
"<p>" +
'<button data-type="faves" data-id="' +
place.id +
'" aria-label="Save ' +
place.place +
'" aria-pressed="' +
props.faves[place.id] +
'">♥</button>' +
'<button data-type="visited" data-id="' +
place.id +
'" aria-label="Visited ' +
place.place +
'" aria-pressed="' +
props.visited[place.id] +
'">✓</button>' +
"</p>" +
"</div>" +
"</div>";
return html;
})
.join("");
};

// Determine if a place should be visible or not based on filters
var getHidden = function (place, props) {
// If filter is 'not visited' and place has been visited, hide
if (props.filter === "not-visited" && props.visited[place.id]) {
return "hidden";
}

// If filter is 'faves' or 'visited' and place has not been favorited or visited, hide
if (props[props.filter] && !props[props.filter][place.id]) {
return "hidden";
}

// Otherwise, show it\
return "";
};

// localStorage
var favesID = "exploreFaves";
var visitedID = "exploreVisited";

// Get items from localStorage
var getFromStorage = function (id) {
var saved = localStorage.getItem(id);
var savedObj = saved ? JSON.parse(saved) : {};
return savedObj;
};

// Save items to localStorage
var saveToStorage = function (items, id) {
localStorage.setItem(id, JSON.stringify(items));
};

// Handle click events
var clickHandler = function (event) {
// Only run on fave buttons
var type = event.target.getAttribute("data-type");
var id = event.target.getAttribute("data-id");
if (!type || !id) return;

// If place is already saved, remove it
// Other, save it
app.data[type][id] = app.data[type][id] ? false : true;
};

// Handle change events
var changeHandler = function (event) {
// Only run on .filters inpts
if (!event.target.closest(".filters")) {
return;
}

// Reactively update filter view
app.data.filter = event.target.value;
};

// Handle render events
var renderHandler = function (event) {
// Save favorites and visited places to localStorage on render
saveToStorage(app.data.faves, favesID);
saveToStorage(app.data.visited, visitedID);
};

// Inits
getPlaces();
document.addEventListener("click", clickHandler);
document.addEventListener("change", changeHandler);
document.addEventListener("reef:render", renderHandler);
</script>