How to dynamically change attributes depending on JSON data? - javascript

I have the following miniapp:
[![enter image description here][1]][1]
When clicking on the elements on the left list, the info should change dynamically on the right div in relation to that clicked element.
I could get it work statically, but I don't know how to make it dynamic.
I have a JSON file with the data, and data is loading correctly and being parsed correctly.
data = '[{"name": "Hotel Sunny Palms","imgUrl": "images/sunny.jpg","rating": 5,"price": 108.00},{"name": "Hotel Snowy Mountains","imgUrl": "images/snowy.jpg","rating": 4,"price": 120.00},{"name": "Hotel Windy Sails","imgUrl": "images/windy.jpg","rating": 3,"price": 110.00},{"name": "Hotel Middle of Nowhere","imgUrl": "images/nowhere.jpg","rating": 4,"price": 199.00}]';
And I have the following HTML file:
<section class="container clear">
<div class="header">
<img class="logo" src="images/lmn-logo-white.svg">
</div>
<div class="inner-container clear">
<aside class="hotels-list">
<ul>
<li class="hotel">1</li>
<li class="hotel">2</li>
<li class="hotel">3</li>
<li class="hotel">4</li>
</ul>
</aside>
<article class="hotel-description">
<div class="hotel-description-container clear">
<div class="hotel-pic-container">
<img id="hotel-pic" src="images/sunny.jpg" height="130px">
</div>
<div class="hotel-info">
<h6 id="hotel-name" >Hotel Sunny Plans </h6>
<div id="hotel-rating" class="hotel-rating"></div>
<div id="hotel-price" class="hotel-price">
$180.00
<span>Total hotel stay</span>
</div>
</div>
</div>
</article>
</div>
</section>
My JS file is this: I get the data to change, but in a static way. Basically what it does is find all the li items and change the info on the right div when clicked.
var hotelData = JSON.parse(data);
document.addEventListener('DOMContentLoaded', function() {
var hotels = document.getElementsByClassName("hotel");
for (var i = 0; i < hotels.length; i++) {
hotels[i].addEventListener('click',function()
{
this.style.background = "#ccc";
this.style.color = "#fff";
var hotelName = document.getElementById("hotel-name");
hotelName.innerHTML = hotelData[this].name;
var hotelPrice = document.getElementById("hotel-price");
hotelPrice.innerHTML = "$" + hotelData[this].price + ".00" + "<span>Total hotel stay</span></div>";
var hotelPic = document.getElementById("hotel-pic");
hotelPic.src=hotelData[this].imgUrl;
var hotelRating = document.getElementById("hotel-rating");
if (hotelData[0].rating == 0) {
hotelRating.style.backgroundPosition = "0px 18px";
}
else if (hotelData[0].rating == 1) {
hotelRating.style.backgroundPosition = "0px 36px";
}
else if (hotelData[0].rating == 2) {
hotelRating.style.backgroundPosition = "0px 54px";
}
else if (hotelData[0].rating == 3) {
hotelRating.style.backgroundPosition = "0px 72px";
}
else if (hotelData[0].rating == 4) {
hotelRating.style.backgroundPosition = "0px 90px";
}
else if (hotelData[0].rating == 5) {
hotelRating.style.backgroundPosition = "0px 108px";
}
});
};
});
Any advice? Thanks!!!

If you are okay with jQuery then here is the quick and very simple solution:
$(function () {
var hotel_list = '';
$.each(data, function(index, hotel) {
hotel_list += '<li class="hotel" data-index="'+ index +'">'+ hotel.name +'</li>';
});
$("aside.hotels-list ul").html(hotel_list);
$(document).on("click", "li.hotel", function () {
var index = $(this).attr('data-index');
load_hotel_info(index);
});
function load_hotel_info(index) {
// Assuming the data variable is global...
if(typeof data[index] !== undefined) {
var hotel = data[index];
$("#hotel-pic").attr('src', hotel.imgUrl);
$("#hotel-name").html(hotel.name);
$("#hotel-rating").html(hotel.rating);
$("#hotel-price").html(hotel.price + '<span>Total hotel stay</span>');
}
}
load_hotel_info(0); // When the page loads for the first time it should show the first item info on the right.
// If you are loading data from ajax then this won't be necessary.
});
In this way the hotel list in the side will also load dynamically. And there isn't much to make it work. Just load the jquery by a script tag before the above code.
I hope it helps.

Related

Selecting a specific class in jQuery

I'm trying to filter different posts kinda page. Each post has many different categories. But the search filter is two-layered, the main filter and then below a more specific selection of filters where I used checkboxes. The problem is that all categories are on the same level. How can I access each selected class based on the user filter input and then output the right post?
Categories and their classes are listed like this:
<span class="category">
<span class="cat Event">Event</span>
<span class="cat Developing">Developing</span>
<span class="cat SQL">SQL</span>
</span>
Where "Event" is in the main filter and the other two are in the second checkbox filter
The project is done in MVC .NET and for filtering functionality, I'm using jQuery
This is how to get each post in my view:
<div class="novice-list">
#foreach (var item in Model.Articles)
{
<div class="novica-container">
<a href="#DataContext.Current.RouteUrlManager.GetModuleLink("article", null, "details", item.Id, item.Title)">
<div class="media">
#{
string slika = string.Empty;
if (item.Id > 166 || item.Id == 159)
{
slika = $"{WellKnownStrings.StorageBaseUrl}{WellKnownStrings.ArticleImageContainer}/{item.FeaturedImage}";
}
else
{
slika = item.FeaturedImageUrl;
}
}
<div class="slika" style="background-image: url('#if (item.FeaturedImageUrl != "") { #slika }');">
</div>
<div class="media-body">
#*content*#
<div class="meta">
<span class="published">#item.DateFormated</span>
<span class="category">
#foreach (var cat in #item.Category)
{
<span class="cat #cat.Title">#cat.Title</span>
}
</span>
</div>
<h2>#item.Title</h2>
<p>#item.Summary</p>
</div>
</div>
</a>
</div>
}
</div>
this is how I get matches from first (Main) filtering:
isCheckedMain = true;
if (isCheckedMain) {
var selectedClass = $(this).attr('class');
// reset the active class on all the buttons
$('#filterOptions li').removeClass('show');
// update the active state on our clicked button
$(this).parent().addClass('show');
if (selectedClass == 'all') {
// show all our items
$('.novica-container').slideDown(1000, "linear");
}
else {
// hide all elements that don't share ourClass
$('.novica-container').hide();
// show all elements that do share ourClass
$('.novica-container').find('span.cat.' + selectedClass).parents('.novica-container').slideDown(1000, "linear");
}
}
And matches for checkbox filter:
$(".checkbox-filter :checkbox").click(function () {
isBoxChecked = true;
if (isCheckedMain && isBoxChecked) {
var selectedBox = $(this).attr('id');
var selectedMain = selectedClass;
if ($('input#' + selectedBox).is(':checked')) {
if ($('span.cat').hasClass(selectedMain)) {
$('.novica-container').hide();
$('span.cat.'+selectedMain).addClass(selectedBox);
$('.checkbox-filter :checkbox:checked').each(function () {
//Get the selected checkbox value
var selectedBox = $(this).attr('id');
$('.novica-container').find('span.cat.' + selectedMain ,'.'+selectedBox).parents('.novica-container').slideDown(700);
});
}
}
else if ($(this).is(':not(checked')) {
$('.novica-container').find('span.cat.' + selectedBox).parents('.novica-container').slideUp(700);
if (($('input[type="checkbox"]:checked').length === 0)) {
isBoxChecked = false;
$('.novica-container').slideDown(1000, "linear");
This is what I have so far, I'm trying to do something with true-false( if one is true, search only with the main filter, if both are true search more accurately with other categories. And I've been stuck here for days trying to merge both sides of the code. They both work separately but not together
Picture of filter
Found a solution for this.
I added all of the categories names one level higher in my View. So that class="category" now has values of all the other categories.
Example: class="category Event Developing SQL"
And then I could just use this jQuery to filter selected posts
$('span.category.' + selectedMain + '.' + selectedBox).parents('.novica-container').slideDown(700);

How to push and pop the details into the array in javascript based on the selection of cards?

I am having 6 bootstrap cards in my web page where every card consists of details like id and content. When I clicked the card the details of the card should be pushed into the array and when I clicked the same card the details should be popped from the array.
My html page in django:
<div class="row">
{% for j in goal %}
<div class="col-4" onclick="getGoal({{j.id}})">
<div class="card4 mt-3" id="room_{{j.id}}" style="width: 12rem; height:9rem;">
<center>
<div class="card-body">
<p class="card-text mt-4" id="cont_{{j.id}}"><b>{{j.goal}}</b></p>
</center>
</div>
</div>
</div>
{% endfor %}
My js code is
var goal = []
function getGoal(id ,content){
if (goal !== []) {
for(var i=0; i<goal.length; i++){
if(goal[i].id == id) {
var index = goal.indexOf(goal[i])
if (index !== -1) {
goal.splice(index, 1);
}
}
}
}else {
var data = {id: id, content: $("#cont_"+id).text()}
var x = JSON.stringify(data)
goal.push(x)
console.log(goal)
}
}
var storedNames = JSON.parse(localStorage.getItem("goal"))
Is the JS code correct for my requirement?
As you can see after adding indentations, you html code is not valide where do you close the center tag ? Else where / how do you call getGoal and why do you have the content parameter if you don't use it ?
var goal = []
function getGoal(id ){
if (goal.length > 0) {
let index = goal.findIndex(x=>x.id == id)
if(index != -1){
goal.splice(index, 1);
}
else{
var data = {id: id, content: $("#cont_"+id).text()}
goal.push(data)
}
}else {
var data = {id: id, content: $("#cont_"+id).text()}
//var x = JSON.stringify(data)
goal.push(data)
console.log(goal)
}
}
var storedNames = JSON.parse(localStorage.getItem("goal"))
try It

jQuery drag-drop working for files, but not folders

I'm using the jquery and jquery UI plugin to drag and drop elements (folders and files) just like in a filebrowser.
I can manage to have the file go 'into' the folder, but not a folder to go into another.
Here is a demo :
There seems to be something conflicting, but I don't know where to look anymore.
The javascript is like this :
$(function () {
// fancytree is part of another script
$("#tree").fancytree({
expandLazy: true,
activate: function (event, data) {
var node = data.node;
if (node.data.href) {
window.open(node.data.href, node.data.target);
}
}
});
/* DRAG AND DROP STARTS HERE */
$(".listitems").draggable();
$(".droppable").droppable({
//preventCollision: true,
drop: function (event, ui) {
var draggableId = ui.draggable.attr("id");
var droppableId = $(this).attr("id");
//alert('FILE'+draggableId+' DROPED INTO '+droppableId);
$(this).append(ui.draggable);
var itemid = ui.draggable.attr('data-itemid');
var folderid = ui.draggable.attr('data-fldmid');
if (typeof folderid == 'undefined') {
folderid = 0;
}
if (typeof itemid == 'undefined') {
itemid = 0;
}
if (typeof droppableId == 'undefined') {
droppableId = 0;
}
$.ajax({
method: "POST",
url: "_ajax/filemanager/dragdrop.php",
//data : 'FileID='+ itemid +'&FolderID='+ droppableId,
data: 'FileID=' + itemid + '&FolderID=' + folderid + '&DropID=' + droppableId,
}).done(function (data) {
var result = $.parseJSON(data);
if (folderid == 0) {
//alert('FILE MOVED - FileID='+ itemid +'&FolderID='+ folderid+'&DropID='+ droppableId);
// Done moving file, hiding it
$("div#" + itemid).hide(500);
} else {
//alert('FOLDER MOVED - FileID='+ itemid +'&FolderID='+ folderid+'&DropID='+ droppableId);
// Done moving directory, hiding it
$("div#" + folderid).hide(500);
}
//$("div#"+folderid).hide(500);
//$("div#"+droppableId).hide(500);
});
}
});
$(".listitems").sortable();
$(".listitems").disableSelection();
var shouldCancel = false;
$('.dragMe').draggable({
containment: '.moveInHere',
revert: function () {
if (shouldCancel) {
shouldCancel = false;
return true;
} else {
return false;
}
}
});
$('.butNotHere').droppable({
over: function () {
shouldCancel = true;
},
out: function () {
shouldCancel = false;
}
});
});
And here is the html
<div class="box-body">
<div class="table-responsive mailbox-messages moveInHere" style="overflow: hidden; min-height:600px;">
<p>
<!--id, data-fldmid and data-itemid were added for testing purposes -->
<div class="boxFile small droppable listitems dragMe drag" id="D.4" data-fldmid='D.4' data-itemid='4'>
<a href="?n=9">
<div class="ffolder small yellow"></div>
</a>
<div class="boxFileTitle">Folder 1 (4)</div>
</div>
<div class="boxFile small droppable listitems dragMe drag" id="D.7" data-fldmid='D.7' data-itemid='7'>
<a href="?n=7">
<div class="ffolder small yellow"></div>
</a>
<div class="boxFileTitle">Folder A (7)</div>
</div>
<p>
<div style="" class="boxFile small listitems butNotHere dragMe drag" id="26" data-itemid='26'>
<img src='image.php?id=26' class='UploadedImageThumb'>
<div class="boxFileTitle">2016-12-12 14.50.14.jpg26</div>
<div class="boxFileOption">Preview | Edit | Trash</div>
</div>
</p>
<p>
<div style="" class="boxFile small listitems butNotHere dragMe drag" id="25" data-itemid='25'>
<img src='image.php?id=25' class='UploadedImageThumb'>
<div class="boxFileTitle">test.jpg25</div>
<div class="boxFileOption">Preview | Edit | Trash</div>
</div>
</p>
</p>
</div>
</div>
The 'butNotHere' class is to prevent files to be on top of each other. All this works fine, except the folder-into-folder dragging as described above.
I found the error, the variable in JS (folderid) had a letter 'D' in front of the real id. I did this during test to check if it was a file being moved or folder. So 'F' or 'D'.
So I changed this line
data-fldmid='D.7'
To this and it worked
data-fldmid='7'

Replace div contents javascript (no jquery)

Every time a selection is made from a dropdown menu, specific data is pulled from facebook and added to different divs. I am trying to update the contents of the div every time a different selection is made, however at the minute, the contents are just appended on after the initial contents.
This is the code that gets data based on a selection and creates the list from the returned data
<script>
city = document.getElementById("citySelection")
city.addEventListener("change", function() {
var selected = this.value;
var eventsList = document.getElementById("events");
if (selected == "None") {
eventsList.style.display = "none";
} else {
eventsList.style.display = "block";
};
if (selected == 'Bristol') {
getBristolEvents();
};
if (selected == 'Leeds') {
getLeedsEvents();
};
if (selected == 'Manchester') {
getManchesterEvents();
};
if (selected == 'Newcastle') {
getNewcastleEvents();
};
});
function createList(response, listId) {
var list = document.createElement('UL')
for (var i = 0; i < 10; i++) {
var events = response.data[i].name
var node = document.createElement('LI');
var textNode = document.createTextNode(events);
node.appendChild(textNode);
list.appendChild(node)
listId.appendChild(list);
}};
</script
This is the div being targeted:
<html>
<div id="events" style="display: none">
<div id="eventsDiv" style="display: block">
<div id="eventsListOne">
<h3 id='headerOne'></h3>
</div>
<div id="eventsListTwo">
<h3 id='headerTwo'></h3>
</div>
<div id="eventsListThree">
<h3 id='headerThree'></h3>
</div>
</div>
</div>
</div>
</html>
I have tried resetting the innerHtml of the div every time the function to get the data from facebook is called:
<script>
function getEventsThree(fbUrl, title) {
var listId = document.getElementById('eventsListThree');
var headerThree = document.getElementById('headerThree');
listId.innerHtml = "";
headerThree.append(title)
FB.api(
fbUrl,
'GET', {
access_token
},
function(response) {
listId.innerHtml = createList(response, listId)
}
)};
</script>
However, that still doesn't reset the contents of the div.
I've looked at other response but they all use jquery which I am not using.
Can anyone advise on the best way to fix this? Thanks.
I think your Hennessy approach is fine. Generate the inner content, then set .innerHTML.
At least one of your problems, maybe the only one, appears to be that you set .innerHTML to the return value of createList, but that function does not return anything.

auto select first ng-repeat element in angularjs?

any idea on how to do this?
i basically have 1 controller set up and if you click on an element, an animation appears above, however, the first element should be active/clicked as soon as the page loads...
some code:
Animation Appears here:
<div class="animation">
<div ng-repeat="theme in themes" ng-show="isActive($index);" ng-if="isActive($index);">
<img id="id_{{ theme.animation_id }}" ng-src="{{ theme.animation_gif_url }}" class="active" />
</div>
</div>
Animation selection here:
<div class="theme-select animated fadeInUp">
<div class="theme-container" ng-repeat="theme in themes" ng-click="showAnimation($index);">
<div id="theme_{{ theme.animation_id }}" class="theme">
<img ng-src="{{ theme.icon_url }}" />
<div class="name">
{{ theme.name }}
</div>
</div>
</div>
</div>
Here's my controller:
themeFunction(function(themeData) {
name = [];
themeID = [];
animationURL = [];
var themes = $scope.themes = themeData.themes;
for (var t = 0; t < themes.length; t++) {
animationURL = themes[t].animation_url;
themeID = themes[t].animation_id;
iconURL = themes[t].icon_url;
name = themes[t].name;
animationGifUrl = themes[t].animation_gif_url;
$scope.themeID = themeID;
if ($scope.themes[t].animation_gif_url == 'NULL' || $scope.themes[t].animation_gif_url == null || $scope.themes[t].animation_gif_url == '.gif') {
// console.log(name + " are null or weird");
$scope.themes[t].animation_gif_url = iconURL;
} else {
$scope.themes[t].animation_gif_url = animationGifUrl;
}
}
$scope._Index = 0;
$scope.isActive = function(index) {
return $scope._Index === index;
};
$scope.showAnimation = function(index) {
selectedTheme = $(this).attr('theme');
console.log('Selected ' + selectedTheme.animation_id);
$scope._Index = index;
};
});
In your controller, after your list loads up, call the showAnimation on the first index
...list loads up
$scope.themes = data;
if (data.length) $scope.showAnimation(0);
Because:
[] == false
So, you can do if simply like this:
if (themes) $scope.showAnimation(0);
If themes is a empty array, not thing will happened.
If themes is a array has at least one theme, will trigger showAnimation function

Categories

Resources