【タブメニュー】コンテンツをカテゴリーごとにソートして表示【ajax:json編】

ページ表示時は全てのカテゴリーの中から最新5件のコンテンツを、タブ切り替え時はカテゴリーごとにソートして、該当カテゴリーの最新5件のコンテンツをフェードインで表示します。
コンテンツはajaxを利用してjsonファイル内のデータを読み込みます。

htmlのコードは下記になります。
カテゴリーのソートはfilter編同様、カスタムデータ属性を利用します。
ajaxを利用してjsonファイル内からデータを読み込み、class=”news-content-all”を付与した空のdivタグ内にコンテンツを表示させます。

<ul class="news_link">
	<li class="active" data-filter="catAll">すべて</li>
	<li data-filter="catInfo">お知らせ</li>
	<li data-filter="catEvent">イベント</li>
	<li data-filter="catRecruit">採用</li>
</ul>
<div class="news-content-all"></div>

jsonのコードは下記になります。
xml編のデータはカテゴリーはバラバラで新しいものから順番に並んでいましたが、jsonのデータはカテゴリーごとに分類され、その該当カテゴリーの中で新しいものから順番に並んでいます。

[
	{
		"cat": "お知らせ",
		"item": [
			{
				"time": "2019/07/02",
				"link": "#",
				"linkTarget": "false",
				"article": "お知らせ01:ダミーテキストダミーテキスト"
			},
			{
				"time": "2019/06/21",
				"link": "#",
				"linkTarget": "false",
				"article": "お知らせ02:ダミーテキストダミーテキスト"
			}
		]
	},
	{
		"cat": "イベント",
		"item": [
			{
				"time": "2019/07/24",
				"link": "https://www.yahoo.co.jp/",
				"linkTarget": "true",
				"article": "イベント情報01:ダミーテキストダミーテキスト"
			},
			{
				"time": "2019/07/18",
				"link": "https://www.msn.com/ja-jp",
				"linkTarget": "false",
				"article": "イベント情報02:ダミーテキストダミーテキスト"
			}
		]
	},
	{
		"cat": "採用ニュース",
		"item": [
			{
				"time": "2019/07/11",
				"link": "#",
				"linkTarget": "false",
				"article": "採用情報01:ダミーテキストダミーテキスト"
			},
			{
				"time": "2019/07/11",
				"link": "",
				"linkTarget": "",
				"article": "採用情報02:ダミーテキストダミーテキスト"
			}
		]
	}
]

続いてCSSのコードです。hasClass編、filter編と全く同じで、変更はありません。

.news_link {
	display: flex;
	margin: 0 0 35px;
	padding: 0;
	list-style-type: none;
}
.news_link li {
	width: 24.7%;
	margin-left: 2px;
	background: #78909c;
	color: #FFFFFF;
	position: relative;
	padding: 20px 6px 20px;
	cursor: pointer;
	text-align: center;
	line-height: 1;
}
.news_link li:first-child {
	margin-left: 0;
}
.news_link li:after {
	content: '';
	position: absolute;
	width: 0;
	height: 0;
	border-left: 10px solid transparent;
	border-right: 10px solid transparent;
	border-top: 16px solid #c3d4dc;
	display: none;
	bottom: -16px;
	left: 50%;
	transform: translateX(-50%);
}
.news_link li.active, .news_link li:hover {
	background: #c3d4dc;
	color: #010101;
	font-weight: bold;
}
.news_link li.active:after, .news_link li:hover:after {
	display: block;
}
.news-content {
	display: flex;
	flex-wrap: nowrap;
	align-items: baseline;
	margin-bottom: 30px;
}
.news-date {
	font-size: 16px;
	margin-right: 20px;
}
.tags {
	margin-right: 20px;
	background: #c3d4dc;
	min-width: 110px;
	font-size: 14px;
	text-align: center;
	padding: 0 6px;
	height: 35px;
	line-height: 35px;
	color: #000000;
}
.news-content .news-r a {
	color: #000;
	transition: color 0.2s ease-in-out;
}
.news-content .news-r a:hover {
	color: #8bc73f;
	transition: color 0.2s ease-in-out;
}

最後にjQueryのコードです。
xml編同様、jsonファイル読み込み部分、読み込み成功時の処理、読み込み失敗時の処理に分かれています。
xml編と異なるのはjsonファイル読み込み成功時の処理です。jsonのデータはxml編と異なりカテゴリーごとに分類されているので、それに対応したデータの取得方法になっています。xml編がeachでデータを取得していたのに対し、jsonはforのネストでデータを取得しています。jsonはデータへのアクセスが直接可能です。xml編のようにDOMでアクセスする必要はありません。
出来上がったコンテンツはカテゴリーごとに日付順で並んでいます。これをsortを利用して日付順に並べます。ここで日付順に並べ替えなければ「すべて」のタブに対応できません。ソートの処理でreturn 0;を記述しているのは、同じ日付の場合はデータの取得順で並べるためです。
ソートの対象はクラス名news-dateの付与された日付のpタグです。そのため変数sortDataの中身は日付のpタグになっています。コンテンツとしては、クラス名news-contentの付与されたdivタグを含めたhtmlが必要です。これをprop(“outerHTML”)を利用して取得し、変数insertContentsSortに格納します。
そして、変数limitの数だけソート後のコンテンツを上から順番にフェードインで表示します。

$(function() {
	$.ajax({
		url: 'js/news.json',
		dataType: 'json',
		cache: false,
	}).done(function(data) {
		var insertContents = '';
		var len1 = data.length;
		for(var i = 0 ; i < len1 ; i++) {
			var len2 = data[i].item.length;
			for(var j = 0 ; j < len2 ; j++) {
				insertContents += '<div class="news-content" data-category="';
				if(data[i].cat == 'お知らせ'){
					insertContents += 'catInfo">';
				}else if(data[i].cat == "イベント"){
					insertContents += 'catEvent">';
				}else if(data[i].cat == "採用ニュース"){
					insertContents += 'catRecruit">';
				}
				insertContents += '<p class="news-date">';
				insertContents += data[i].item[j].time;
				insertContents += '</p>';
				insertContents += '<p class="tags">';
				insertContents += data[i].cat;
				insertContents += '</p>';
				insertContents += '<p class="news-r">';
				if(data[i].item[j].link == ''){
					insertContents += data[i].item[j].article;
				}else{
					insertContents += '<a href="' + data[i].item[j].link + '"';
					insertContents += ((data[i].item[j].linkTarget == "true") ? ' target="_blank"' : '') + '>';
					insertContents += data[i].item[j].article;
					insertContents += '</a>';
				}
				insertContents += '</p>';
				insertContents += '</div>';
			}
		}

		var sortData = $('.news-date' , insertContents).sort(function(a,b) {
			if($(a).text() < $(b).text()) return 1;
			if($(a).text() > $(b).text()) return -1;
			return 0;
		});
		var insertContentsSort = '';
		$(sortData).each(function(){
			insertContentsSort += $(this).parent().prop("outerHTML");
		});

		var newsLink = $(".news_link li");
		var limit = 5;
		for(var i = 0 ; i < limit ; i++) {
			var limitNews = $(insertContentsSort)[i];
			$(limitNews).appendTo('.news-content-all').hide().fadeIn();
		}
		$(newsLink).click(function(){
			$(newsLink).removeClass("active");
			$(this).addClass("active");
			var btnFilter = $(this).attr('data-filter');
			if (btnFilter == 'catAll') {
				$(".news-content").remove();
				for(i = 0 ; i < limit ; i++) {
					limitNews = $(insertContentsSort)[i];
					$(limitNews).appendTo('.news-content-all').hide().fadeIn();
				}
			} else {
				$(".news-content").remove();
				for(i = 0 ; i < limit ; i++) {
					limitNews = $(insertContentsSort).filter('[data-category = "' + btnFilter + '"]')[i];
					$(limitNews).appendTo('.news-content-all').hide().fadeIn();
				}
			}
		});

	}).fail(function(jqXHR, textStatus) {
			var errorMessage = '';
			errorMessage += '<p>データの読み込みに失敗しました。';
			errorMessage += 'ステータスコード:' + jqXHR.status + '、';
			errorMessage += 'ステータス:' + textStatus + '</p>';
			$(errorMessage).appendTo('.news-content-all');
	});
});
タイトルとURLをコピーしました