jquery each selector and ajax not producing the right results - javascript

I am trying to simplify my code but running into issues where it is not working when it place in an each loop.
Here is what I am trying to do:
- html has n parent DIV that generates a report via an AJAX call to pull data
- each div respective to report utilizes a data attribute to define which report to pull
- based no the results of the report, it should populate the html with the respective results.
HTML Code (to simplify, using n = 2):
<div class="widget-box widget-hits card no-border bg-white no-margin" data-widget-report="widget-hits">
<div class="container-xs-height full-height">
<div class="row-xs-height">
<div class="col-xs-height col-top">
<div class="card-header top-left top-right">
<div class="card-title text-black hint-text">
<span class="font-montserrat fs-11 all-caps">Weekly Hits
<i class="far fa-chevron-right p-l-5"></i>
</span>
</div>
<div class="card-controls">
<ul>
<li>
<a data-toggle="refresh" class="card-refresh text-black" href="#">
<i class="far fa-circle fa-xs"></i>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="row-xs-height ">
<div class="col-xs-height col-top relative">
<div class="row">
<div class="col-sm-6">
<div class="p-l-20 widget-total">
<h3 class="no-margin p-b-5"></h3>
<p class="small hint-text m-t-5">
<span class="label m-r-5">%</span>
</p>
</div>
</div>
<div class="col-sm-6">
</div>
</div>
<div class="widget-chart"></div>
</div>
</div>
</div>
</div>
<div class="widget-box widget-sales card no-border bg-white no-margin" data-widget-report="widget-sales">
<div class="container-xs-height full-height">
<div class="row-xs-height">
<div class="col-xs-height col-top">
<div class="card-header top-left top-right">
<div class="card-title text-black hint-text">
<span class="font-montserrat fs-11 all-caps">Weekly Sales
<i class="far fa-chevron-right p-l-5"></i>
</span>
</div>
<div class="card-controls">
<ul>
<li>
<a data-toggle="refresh" class="card-refresh text-black" href="#">
<i class="far fa-circle fa-xs"></i>
</a>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="row-xs-height ">
<div class="col-xs-height col-top relative">
<div class="row">
<div class="col-sm-6">
<div class="p-l-20 widget-total">
<h3 class="no-margin p-b-5"></h3>
<p class="small hint-text m-t-5">
<span class="label m-r-5">%</span>
</p>
</div>
</div>
<div class="col-sm-6">
</div>
</div>
<div class="widget-chart"></div>
</div>
</div>
</div>
</div>
JS:
$('.widget-box').each(function() {
$widget_report = $(this).data('widget-report');
if ($widget_report !== undefined) {
$.ajax({
type: 'get',
url: '/admin/reports/' + $widget_report,
dataType: 'json',
success:
function(data) {
if (data.success) {
var labelsData = [];
var seriesData = [];
var trend = data.trend * 100;
widget_class = '.' + $widget_report + ' .widget-chart';
console.log(widget_class);
$(this).find('.widget-total h3').text(data.total);
$(this).find('.widget-total p span').text(trend + '%');
trend_span = $(this).find('.widget-total p').children('span');
if(data.trend > 0) {
$(this).find('.widget-total p span.label').addClass('label-success');
$(this).find('.widget-total p').text('Higher');
}
else {
$(this).find('.widget-total p span.label').addClass('label-important');
$(this).find('.widget-total p').text('Lower');
}
$(this).find('.widget-total p').prepend(trend_span);
$.each(data.values, function(key, value){
date = new Date(value.label + 'T00:00:00');
labelsData.push(date.getMonth() + 1 + '/' + date.getDate());
seriesData.push(value.value);
});
chartData = {
labels: labelsData,
series: [seriesData]
}
alert(widget_class);
new Chartist.Bar(widget_class, chartData, {
axisX: {
showGrid: false
},
axisY: {
showGrid: false,
showLabel: false
}
});
}
}
});
}
});
Here are the problems I've encountered:
$(this).find('.widget-total h3').text is not updating the respective DIV group
widget_class for some reason is always returning the last DIV group... even if the last DIV group was returning data.success = false. Ex: above would return widget-sales twice and not widget-hits and then widget-sales.
I am scratching my head on this one... I am able to get this to work without the .each loop and distinctively create one for each... but was hoping to make this universal and allow the control rely on the data-widget-report attribute on the html.
Is this the proper approach?
Any help / direction is appreciated...

Add var in front of widget_class and $widget_report so they are scoped to the function instead of global. I think that will fix your problem. Right now $widget_report gets replaced by the last widget even before the ajax calls are completed.
As for the $(this) not working, you have to assign it to a variable before you make the ajax call.
$('.widget-box').each(function() {
var widgetBoxElement = $(this);
var $widget_report = $(this).data('widget-report');
if ($widget_report !== undefined) {
$.ajax({
type: 'get',
url: '/admin/reports/' + $widget_report,
dataType: 'json',
success:
function(data) {
if (data.success) {
// use widgetBoxElement here instead of $(this)
}
}
});
}
});

Related

How to look for child elements in a collection

im very new to javascript and probably thats a silly question. What I am trying to achieve is to loop through rows of a "table", get the innerHTML of specific child nodes and multiply them together.
The html looks like this:
<div class="parent">
...
<div class="countChild">
<div class="container">
<span class="count">5</span>
</div>
</div>
<div class="valueChild">
<span class="value">30</span>
</div>
...
</div>
<div class="parent">
...
<div class="countChild">
<div class="container">
<span class="count">2</span>
</div>
</div>
<div class="valueChild">
<span class="value">30</span>
</div>
...
</div>
To be specific: I want to get both the values inside the'countChild' and the 'valueChild'. In this example those are 5 and 30 for the first row and for the second row its 2 and 30. Then perform a muiltiplication.
What I tried to do is to get all the parent nodes and then iterating through them to get the child nodes.
const parents = document.getElementsByClassName('parent');
for(var row in parents) {
var count = row.getElementsByClassName('countChild').lastChild.innerHTML;
var value = row.getElementsByClassName('valueChild').lastChild.innerHTML;
....
}
However the debugger already throws an error when im trying to get the childs. The error message is row.getElemenstByClassName is not a function. I guess the collection cannot be used like this and my understanding of how to use js to get information from the document is wrong.
Edit: This is what the tree looks like
<div class="listing-entry">
<div class="value-container d-none d-md-flex justify-content-end">
<div class="d-flex flex-column">
<div class="d-flex align-items-center justify-content-end">
<span class="font-weight-bold color-primary small text-right text-nowrap">30</span>
</div>
</div>
</div>
<div class="count-container d-none d-md-flex justify-content-end mr-3">
<span class="item-count small text-right">5</span>
</div>
</div>
You should access parents like an array (not really array but you can cast it to one). Btw, I encourage you to use querySelectorAll and querySelector instead of getElementsByClassName
const parents = document.querySelectorAll(".parent")
parents.forEach(function(row) {
var countChild = row.querySelector(".countChild")
var valueChild = row.querySelector(".valueChild")
var count = countChild ? countChild.innerText : 0
var value = valueChild ? valueChild.innerText : 0
console.log(count, value, count * value)
})
<div class="parent">
...
<div class="countChild">
<div class="container">
<span class="count">5</span>
</div>
</div>
<div class="valueChild">
<span class="value">30</span>
</div>
...
</div>
<div class="parent">
...
<div class="countChild">
<div class="container">
<span class="count">2</span>
</div>
</div>
<div class="valueChild">
<span class="value">30</span>
</div>
...
</div>
Edit: I'm using querySelector instead of getElementsByClassName, and checking if child exists before accessing its innerText property.
Edit: here's a function to get all text nodes under a specific node. Then you can combine them and trim the result to get the value you want.
function textNodesUnder(node) {
var all = [];
for (node = node.firstChild; node; node = node.nextSibling) {
if (node.nodeType == 3) {
all.push(node);
} else {
all = all.concat(this.textNodesUnder(node));
}
}
return all;
}
var nodes = textNodesUnder(document.querySelector(".listing-entry"))
var texts = nodes.map(item => item.nodeValue.trim())
console.log(texts)
<div class="listing-entry">
<div class="value-container d-none d-md-flex justify-content-end">
<div class="d-flex flex-column">
<div class="d-flex align-items-center justify-content-end">
<span class="font-weight-bold color-primary small text-right text-nowrap">30</span>
</div>
</div>
</div>
<div class="count-container d-none d-md-flex justify-content-end mr-3">
<span class="item-count small text-right">5</span>
</div>
</div>

how to loop through an array to hide items

i have an html form in which the user clicks on the plus sign and it shows you a list of items, if you click on a minus sign it will hide those items
as follows:
<div repeat.for="categoryGrouping of categoryDepartment">
<div class="row">
<div class="col s12 m3 l3">
<div class="card blue-grey darken-1">
<div class="card-content" style="padding:10px">
<span class="card-title white-text truncate">${categoryGrouping.name}</span>
<a if.bind="categoryGrouping.hideDetails" class="btn-floating halfway-fab waves-effect waves-light" click.delegate="Activate(user, categoryGrouping)"><i class="material-icons">add</i></a>
<a if.bind="!categoryGrouping.hideDetails" class="btn-floating halfway-fab waves-effect waves-light" click.delegate="DeActivate(user, categoryGrouping)"><i class="material-icons">remove</i></a>
</div>
</div>
</div>
</div>
<div repeat.for="categoryGroupingTypes of categoryDepartmentTypes">
<div class="row" if.bind="!categoryGrouping.hideDetails">
<div repeat.for="user of categoryGroupingTypes.users" class="col s12 m3 l3 ">
<div class="card blue-grey darken-1" click.delegate="GetCrewProfiles(user)">
<div class="card-content">
<span class="card-title white-text truncate">${user.firstName} ${user.lastName}</span>
<p>${user.emailAddress || 'mock#email.com'}<br /></p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
in type script
async Activate(user: userListModel[], department: any) {
this.categoryDepartment.forEach(x => {
x.hideDetails = true;
});
this.categoryDepartmentTypes = await this.getTypes(user, department.name);
department.hideDetails = false;
}
async DeActivate(user: userListModel[], department: any) {
department.hideDetails = true;
}
this.categoryDepartment stores my array as follows:
0:{hideDetails:true, name:"Hello"}
1:{hideDetails:false,name:"Test"}
so the above looks as the following image
so now for example if i had to click on the "Hello" plus sign while the details for "Test" is open it would close "Test".
How can i loop through the departments to have it remain open but only when i click the minus then it should close.
I need to pass in the department name to this await this.getTypes(user, department.name); method, so only the item i click on should pass that name in and not all the department names.
does anyone know how i can achieve this?
i tried doing the following
if (this.categoryDepartment.find(x => x.name == department.name)){
this.categoryDepartmentTypes = await this.getTypes(user, department.name);
department.hideDetails = false;
}
but it still does the same thing, it closes on the next item i click on
You hide everything in this loop:
this.categoryDepartment.forEach(x => {
x.hideDetails = true;
});
So you can remove it.

MVC Navigate to Another Page With JavaScript

When I click on a city in the map on my homepage, the corresponding screen opens as a pop-up. Then if I click on the body of this opened window I want to go to the detail page of the relevant project. But I could not set the JavaScript code.
My Index.cshtml:
#{ Html.RenderPartial("Map");}
<div class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog" role="document">
<div class="modal-content">
<form>
<div class="modal-body popupList">
</div>
</form>
</div>
</div>
<script>
$('g [type=city]').click(function (el) {
$('#turkey-map g [type="city"]').attr('activeChart', 0)
$(this).attr('activeChart', 1);
var cityid = $(this).attr('city_id');
$('.popupList').html('preparing content...');
$.ajax({
method: "get",
url: '#Url.Action("ProjectListPartial", "Home")',
data: { cityID: cityid, UnitID: #UnitID }
})
.done(function (msg) {
$('.popupList').html(msg);
$(".modal").modal();
});
});
</script>
And my ProjectListPartial.cshtml:
<div class="ProjectsPartial">
#foreach (var item in Model)
{
<div class="ProjectPartialBody" data-id="#item.ID">
<div class="portlet-body">
<div class="mt-element-list">
<div class="mt-list-head list-news ext-1 font-white bg-grey-gallery">
<div class="list-head-title-container">
<h5 class="list-title">#item.tbl_Unit.Name</h5>
<br />
<h3 class="list-title">#item.Name</h3>
</div>
</div>
<div class="mt-list-container list-news ext-1">
<ul>
<li class="mt-list-item">
<div class="list-icon-container">
<a href="#Url.Action("Detail", "Project", new {ID = item.ID })">
<i class="fa fa-angle-right"></i>
</a>
</div>
<div class="list-datetime bold font-red"> Sözleşme Başlangıç ve Bitiş Tarihleri </div>
<div class="list-datetime bold font-red"> #((item.SozBasTarihi ?? DateTime.Now).ToString("dd/MM/yyyy")) / #((item.SozBitisTarihi ?? DateTime.Now).ToString("dd/MM/yyyy")) </div>
<div class="list-item-content">
<div class="form-group">
<label>Nakdi Tamamlanma Oranı: %#item.NakdiTamOrani</label>
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-info" role="progressbar" style="width: #(item.NakdiTamOrani)%;"></div>
</div>
</div>
<div class="form-group">
<label>Fiziki Tamamlanma Oranı: %#item.FizikiTamOrani</label>
<div class="progress progress-striped active">
<div class="progress-bar progress-bar-info" role="progressbar" style="width: #(item.FizikiTamOrani)%;"></div>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div>
</div>
}
</div>
As you can see, when I click city on the map, pop-up windows is open. What I want to do is when I click on pop-up body; I want to go to the detail page of the relevant project with JavaScript. I've try with JavaScript but I failed.
My JavaScript code in ProjectListPartial.cshtml page:
<script>
$('div.ProjectPartialBody').click(function (el) {
var projectid = $(this).data('id');
$.ajax({
method: "get",
url: '#Url.Action("Detail", "Project")',
data: { projectID: projectid }
})
.done(function (msg) {
// I do not know what to write here.
});
});
</script>
try this:
<script>
//pass vale in url
function navigateURL(value) {
var url = '#Url.Action("Index", "ProductView", new {id = "_value" })';
var urlWithValue = url.replace('_value', value);
window.location.href = urlWithValue;
}
</script>

jQuery callback function to check number of child elements on element click

I have a set of "div" whose children count I want to check when a user fadeOut images under that div block, if the all childrens have be closed out i want to call the function: kind of like:
edited: the current code always alerts YES whenever the div is faded,
how do i destroy the DOM entirely without having to use :visible
filter. getting rid of the entire card class after fading out
considering the HTML:
<div class='scrolling-wrapper'>
<div class='card'>
<div class='panel panel-primary'>
<div class='panel-body'>
<div class='img-wrap'>
<span class='close-x'> × </span>
<img width='100%' id='3' class='' src='resizer/resizer.php?file=profiles/images/default_cover.jpg&width=700&height=400&action=resize&watermark=bridgoo&watermark_pos=tl&color=255,255,255&quality=100' />
</div>
<div class='title h5'>
<span class='user-popover'>
<a href='/groupstomason/'><b>tomason</b></a>
</span>
<br/>
<small class='small-text'>for max tomason
</small>
</div>
</div>
<div class='panel-heading'>
<button class='btn btn-primary'> <span class='fa fa-plus-circle fa-fw'> </span>Join </button>
</div>
</div>
<div class='card-group-holder' style='width:250px; background-color:inherit;'>
</div>
<div class="card"> another card</div>
<div class="card"> another card</div>
<div class="card"> another card</div>
</div>
and the jquery below:
$('.img-wrap .close-x').on('click', function() {
var card = $(this).closest('.card');
card.fadeOut('slow', function() {
var cardWrapper = $(this).closest('.card').closest('scrolling-wrapper');
var cardcount = cardWrapper.children('.card');
if (cardcount.length < 1) alert('yes');
});
});
when the <span class = 'close-x'> × </span> is clicked the
entire <div class='card'> is fadedOut, then on fadeout, if no more
cards exist or the last cards have been faded, then alert('yes');
Assuming that multiple .card elements are nested in the same parent, you can check if all the siblings have faded out.
In your original markup, you have an unclosed </div>, which causes the .card elements not to be siblings of each other, I believe this is a typo on your part, since it is the most parsimonious explanation.
Since .fadeOut() hides the element, you can simply check if the filtered set of :visible returns a length of 1 or more:
$('.img-wrap .close-x').on('click', function() {
var card = $(this).closest('.card');
card.fadeOut('slow', function() {
var cardWrapper = $(this).closest('.scrolling-wrapper');
var cardcount = cardWrapper.children('.card');
if (cardcount.filter(':visible').length < 1) {
console.log('All cards have faded out');
}
});
});
Here is a proof-of-concept example:
$(function() {
$('.close').on('click', function() {
var card = $(this).closest('.card');
card.fadeOut('slow', function() {
// Get wrapping ancestor
var cardWrapper = $(this).closest('.scrolling-wrapper');
var cardcount = cardWrapper.children('.card');
// Filter out those that are not visible, and check for remaining visible cards
if (cardcount.filter(':visible').length < 1) {
console.log('All cards have faded out');
}
});
});
});
/* Just styles for a dummy call-to-action element in .card */
span.close {
cursor: pointer;
color: steelblue;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="scrolling-wrapper">
<div class="card">Card 1. <span class="close">Click to hide me.</span></div>
<div class="card">Card 2. <span class="close">Click to hide me.</span></div>
<div class="card">Card 3. <span class="close">Click to hide me.</span></div>
<div class="card">Card 4. <span class="close">Click to hide me.</span></div>
<div class="card">Card 5. <span class="close">Click to hide me.</span></div>
</div>
In your callback you may simply test if at least a card is visible:
if ($(this).closest('.card').siblings('.card:visible').length < 1) alert('yes');
$('.img-wrap .close-x').on('click', function () {
var card = $(this).closest('.card');
card.fadeOut('slow', function () {
if ($(this).closest('.card').siblings('.card:visible').length < 1) console.log('yes');
});
});
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<script src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<div class='scrolling-wrapper'>
<div class='card'>
<div class='panel panel-primary'>
<div class='panel-body'>
<div class='img-wrap'>
<span class='close-x'> × </span>
<img width='100%' id='3' class=''
src='resizer/resizer.php?file=profiles/images/default_cover.jpg&width=700&height=400&action=resize&watermark=bridgoo&watermark_pos=tl&color=255,255,255&quality=100'/>
</div>
<div class='title h5'>
<span class='user-popover'>
<a href='/groupstomason/'><b>tomason</b></a>
</span>
<br/>
<small class='small-text'>for max tomason
</small>
</div>
</div>
<div class='panel-heading'>
<button class='btn btn-primary'><span class='fa fa-plus-circle fa-fw'> </span>Join</button>
</div>
</div>
<div class='card-group-holder' style='width:250px; background-color:inherit;'>
</div>
</div>
<div class='card'>
<div class='panel panel-primary'>
<div class='panel-body'>
<div class='img-wrap'>
<span class='close-x'> × </span>
<img width='100%' id='3' class=''
src='resizer/resizer.php?file=profiles/images/default_cover.jpg&width=700&height=400&action=resize&watermark=bridgoo&watermark_pos=tl&color=255,255,255&quality=100'/>
</div>
<div class='title h5'>
<span class='user-popover'>
<a href='/groupstomason/'><b>tomason</b></a>
</span>
<br/>
<small class='small-text'>for max tomason
</small>
</div>
</div>
<div class='panel-heading'>
<button class='btn btn-primary'><span class='fa fa-plus-circle fa-fw'> </span>Join</button>
</div>
</div>
<div class='card-group-holder' style='width:250px; background-color:inherit;'>
</div>
</div>
</div>

call Load more function for active tab

I'm trying to develop a load more function for a specific tab pane, in this case, the active tab pane. I'm having issues with this jquery function because I'm calling the load more in the end of all tabs, and in my JS function I can't figure out how to load after the pane that is active, in which the button was clicked. This way I keep loading the questions in the last pane, but I couldnt print without var lastItem = $('div.question-col .question-summary:last');
$(document).ready(function () {
$(".load-more").on('click', function (e) {
var tab = $(this).data('tab');
var next_page = $(this).data('next-page');
console.log(next_page);
console.log(tab);
$.get($(this).data('url') + '?tab=' + tab + '&page=' + next_page, function (data) {
addNewQuestions($.parseJSON(data));
});
$(this).data('next-page', parseInt(next_page) + 1);
});
siteStats();
});
function addNewQuestions(objects) {
$.each(objects, function (i, object) {
console.log(object);
var lastItem = $('div.question-col .question-summary:last');
var newLine = lastItem.clone(true);
var newObject = newLine.find('.question-info');
updateTitleAndLink(newObject.find('.summary a'), object);
updateCreationDate(newObject.find('.question-updated-at'), object);
updateQuestionAnswers(newObject.find('.question-answers'), object);
updateAnswerCount(newObject.find('.answers-count'), object);
updateViewsCount(newObject.find('.views-count'), object);
updateVotesCount(newObject.find('.votes-count'), object);
updateSolvedStatus(newObject.find('.status'), object)
lastItem.after(newLine);
});
}
The update functions are not relevant to this case, I guess.
<div id="tabs" class="tab-content">
<ul>
<li>Recent Questions</li>
<li>Unanswered Questions</li>
<li>Top Scored Questions</li>
</ul>
{if empty($recent_questions)}
<div class = "col-sm-12" style = "text-align: center"><strong>No questions to load!</strong></div>
{/if}
{if !empty($recent_questions)}
<div id="recent_questions" class="question-col">
<!-- Questions come here -->
<div class = "load-more"
data-next-page = "1"
data-url = "{url('controller/api/questions/load_more_questions')}"
data-tab = "recent_questions">
<a id="loadMore">
Load More...
</a>
</div>
</div>
{/if}
<div id="unanswered_questions">
<!-- Questions come here -->
<div class = "load-more"
data-next-page = "1"
data-url = "{url('controller/api/questions/load_more_questions')}"
data-tab = "unanswered_questions">
<a id="loadMore">
Load More...
</a>
</div>
</div>
<div id="top">
<!-- Questions come here -->
<div class = "load-more"
data-next-page = "1"
data-url = "{url('controller/api/questions/load_more_questions')}"
data-tab = "top_scored_questions">
<a id="loadMore">
Load More...
</a>
</div>
</div>
//Questions come here - Question template
<div class="question-summary narrow">
<div class="question-info col-md-12">
<div class="votes">
<div class="votes-count">
<span title="{$question['votes_count']} votes">
{if $question['votes_count']}
{$question['votes_count']}
{else}
0
{/if}
</span>
</div>
<div>votes</div>
</div>
<div {if $question['solved_date']}
class="status answered-accepted"
{else}
class="status answer-selected"
{/if}
title="one of the answers was accepted as the correct answer">
<div class="answers-count">
<span title="{$question['answers_count']} answer">{$question['answers_count']}</span></div>
<div>answer</div>
</div>
<div class="views">
<div class="views-count">
<span title="{$question['views_counter']} views">{$question['views_counter']}</span></div>
<div>views</div>
</div>
<div class="summary question-title">
<h3>
<a href="{questionUrl($question['publicationid'])}"
data-base-question-url = "{questionUrl('')}"
style="font-size: 15px; line-height: 1.4; margin-bottom: .5em;">
{$question['title']}
</a>
</h3>
</div>
<div class = "statistics col-sm-12 text-right" style="padding-top: 8px">
<span>
<i class = "glyphicon glyphicon-time"></i>
<span class="question-updated-at">{$question['creation_date']}</span>
</span>
<span>
<i class = "glyphicon glyphicon-comment"></i>
<span class="question-answers">{$question['answers_count']}</span>
</span>
</div>
</div>
</div>
My question is: is there any way to put my loaded content after the last item of the active pane?
Kind regards

Categories

Resources