التنقل في الفئات التجارية

حصل خطأ عند معالجة القالب.
The following has evaluated to null or missing:
==> serviceLocator.findService("com.marketplace.category.service.CategoryLocalService")  [in template "20096#20121#36178" at line 2, column 33]

----
Tip: If the failing expression is known to legally refer to something that's sometimes null or missing, either specify a default value like myOptionalVar!myDefault, or use <#if myOptionalVar??>when-present<#else>when-missing</#if>. (These only cover the last step of the expression; to cover the whole expression, use parenthesis: (myOptionalVar.foo)!myDefault, (myOptionalVar.foo)??
----

----
FTL stack trace ("~" means nesting-related):
	- Failed at: #assign categoryLocalService = servic...  [in template "20096#20121#36178" at line 2, column 1]
----
1<#assign assetCategoryLocalService = serviceLocator.findService("com.liferay.asset.kernel.service.AssetCategoryLocalService")> 
2<#assign categoryLocalService = serviceLocator.findService("com.marketplace.category.service.CategoryLocalService") /> 
3<#assign assetEntryLocalService=serviceLocator.findService("com.liferay.asset.kernel.service.AssetEntryLocalService") /> 
4<#assign cpDefinitionLocalService=serviceLocator.findService("com.liferay.commerce.product.service.CPDefinitionLocalService") /> 
5<#assign assetEntryAssetCategoryRelLocalService = serviceLocator.findService("com.liferay.asset.entry.rel.service.AssetEntryAssetCategoryRelLocalService") /> 
6<#assign publicSiteURL = themeDisplay.getPortalURL() + themeDisplay.getPathFriendlyURLPublic() + layout.getGroup().friendlyURL /> 
7 
8 
9<#function getPublishedProductCount categoryId> 
10	<#assign productCount=0 /> 
11	<#assign  assetEntryAssetCategoryRel = assetEntryAssetCategoryRelLocalService.getAssetEntryAssetCategoryRelsByAssetCategoryId(categoryId) /> 
12	<#list assetEntryAssetCategoryRel as assetEntryCategoryRel> 
13		<#assign assetEntry = assetEntryLocalService.fetchAssetEntry(assetEntryCategoryRel.getAssetEntryId()) /> 
14       <#if assetEntry??> 
15					<#assign classPK = assetEntry.getClassPK() /> 
16				  <#assign cpDefinition = cpDefinitionLocalService.getCPDefinition(classPK) /> 
17				 <#if cpDefinition??> 
18             <#if cpDefinition.isPublished() && cpDefinition.getStatus() == 0> 
19                 <#assign productCount = productCount + 1 /> 
20             </#if> 
21         </#if> 
22			</#if>  
23	</#list> 
24  <#return productCount?number /> 
25</#function> 
26 
27<#assign subCategoryCount = 0 /> 
28 
29<script> 
30	var categoriesMap = new Map(); 
31</script> 
32 
33<#macro renderCategories categories> 
34	<#list categories as category> 
35		<#assign customCategoryObj = categoryLocalService.findByFBYAssetCategoryId(category.getCategoryId()) /> 
36		<#assign isCategoryActive = customCategoryObj.getIsActive() && customCategoryObj.getCategoryApprovalStatus() == "Approved" /> 
37		<#if isCategoryActive> 
38			<#assign subCategoryList = assetCategoryLocalService.getChildCategories(category.getCategoryId()) /> 
39			<#assign cUrl = "${publicSiteURL}/market?category=${category.getCategoryId()}" /> 
40			<#assign productCount = getPublishedProductCount(category.getCategoryId()) /> 
41 
42			<#if productCount gt 0> 
43				<script> 
44					categoriesMap.set(${category.getCategoryId()}, '${category.getName()}'); 
45				</script> 
46				<a href="${cUrl}" class="text-secondary">${category.getName()}</a> 
47				<br> 
48			<#else /> 
49				<span class="text-secondary">${category.getName()}</span><br> 
50			</#if> 
51 
52			<#assign subCategoryCount = subCategoryCount?number + 1 /> 
53 
54			<#if subCategoryList?has_content> 
55				<@renderCategories categories=subCategoryList /> 
56			</#if> 
57		</#if> 
58	</#list> 
59</#macro> 
60 
61<div class="container">		 
62	<nav class="navbar navbar-light bg-light category-nav justify-content-between"> 
63		<a class="navbar-brand"><b>All Category</b></a> 
64		<form class="form-inline"> 
65			<div class="input-group"> 
66				<div class="input-group-prepend"> 
67					<span class="input-group-text " id="basic-addon1">  <img src="/o/buycorp-classic-theme/images/icon/search-icon.png" ></span> 
68				</div> 
69				<input class="form-control clp-search mr-sm-2 p-0"  type="search" id="categorySearch" list="searchResults" placeholder="Search By Category Name" aria-label="Search" aria-describedby="basic-addon1"> 
70			</div> 
71		</form> 
72	</nav> 
73	<div class="search-card d-none"> 
74		<div id="searchResults"></div> 
75	</div> 
76 
77	<div class="d-flex flex-wrap maxBoxScroll" id="<@portlet.namespace />cpAssetCategoryNavigation"> 
78		<#if entries?has_content> 
79			<#list entries as category> 
80				<#assign customCategoryObj = categoryLocalService.findByFBYAssetCategoryId(category.getCategoryId()) /> 
81				<#assign isCategoryActive = customCategoryObj.getIsActive() && customCategoryObj.getCategoryApprovalStatus() == "Approved" /> 
82				<#if isCategoryActive> 
83					<#assign subCategoryCount = 0 /> 
84					<div class="card clp-card" > 
85						<div class="card-body"> 
86							<#assign productCount = getPublishedProductCount(category.getCategoryId()?number) /> 
87							<#assign subCategoryList = assetCategoryLocalService.getChildCategories(category.getCategoryId()) /> 
88							<#assign cUrl = "${publicSiteURL}/market?category=${category.getCategoryId()}" /> 
89 
90							<#if productCount gt 0> 
91								<script> 
92									categoriesMap.set(${category.getCategoryId()}, '${category.getName()}'); 
93								</script> 
94								<h3 class="card-title mb-2"><b><a href="${cUrl}"><strong>${category.getName()}</strong></a></b></h3> 
95							<#else /> 
96								<h3 class="card-title mb-2"><b><strong>${category.getName()}</strong></b></h3> 
97							</#if> 
98 
99							<#if subCategoryList?has_content> 
100								<@renderCategories categories=subCategoryList /> 
101							</#if> 
102						</div> 
103					</div> 
104				</#if> 
105			</#list> 
106		</#if> 
107	</div> 
108</div> 
109 
110<script> 
111    
112	const searchElement = document.getElementById('categorySearch'); 
113 
114	const searchData = (event) => { 
115		const filteredMap = new Map( 
116			[...categoriesMap].filter(([k, v]) => v.toLowerCase().includes(event.target.value.toLowerCase())) 
117		); 
118		showResults(filteredMap); 
119	}; 
120 
121	const debounce = (callback, waitTime) => { 
122		let timer; 
123		return (...args) => { 
124			clearTimeout(timer); 
125			timer = setTimeout(() => { 
126				callback(...args); 
127			}, waitTime); 
128		}; 
129	}; 
130 
131	const debounceHandler = debounce(searchData, 1000); 
132	searchElement.addEventListener('input', debounceHandler); 
133 
134	var showResults = filteredCategories => { 
135 
136		let searchResultsList = document.getElementById('searchResults'); 
137		searchResultsList.innerHTML = ''; 
138 
139		if(searchElement.value.trim().length == 0) { 
140			$('.search-card').addClass('d-none'); 
141			return; 
142
143 
144		$('.search-card').removeClass('d-none'); 
145		 
146		if (filteredCategories.size == 0) { 
147			let noResultItem = document.createElement('div'); 
148			noResultItem.textContent = 'No categories found'; 
149			searchResultsList.appendChild(noResultItem); 
150		} else { 
151			filteredCategories.forEach((value, key) => { 
152				let listItem = document.createElement('li'); 
153				listItem.setAttribute('categoryid', key); 
154 
155				let anchor = document.createElement('a'); 
156				anchor.setAttribute('href', '${publicSiteURL}/market?category=' + key + ''); 
157				anchor.innerText = value; 
158 
159				listItem.appendChild(anchor); 
160 
161				searchResultsList.appendChild(listItem); 
162			}); 
163
164 
165	}; 
166 
167var showHideCategories = currObj => { 
168	let moreCategoriesSection = $(currObj).siblings('.more-categories').eq(0); 
169	if (moreCategoriesSection.hasClass('d-none')) { 
170		moreCategoriesSection.removeClass('d-none'); 
171		$(currObj).text('Less'); 
172	} else { 
173		moreCategoriesSection.addClass('d-none'); 
174		$(currObj).text('More'); 
175
176}; 
177 
178</script> 
179	 
180	 
181<style> 
182 .text-secondary { font-weight: 400;   font-size: 12px; line-height:18px; } 
183 .card-title {  font-weight: 600;  font-size: 14px; line-height:20px;} 
184	.card-title a:hover {  color:#2B4960} 
185 .clp-card {border-radius: 8px;width: calc(20% - 20px); min-height:230px; max-height:230px; height:auto;  margin: 10px; 
186   box-sizing: border-box; border: 1px solid #DDDDDD; overflow-y:auto;} 
187 .category-nav { background:transparent !important;   margin:30px 0px 30px 0px;} 
188 .navbar-brand b {font-family: roboto;font-weight: 600;font-size: 24px;     color: #373737;	} 
189 .clp-search { border-left-style: none;} 
190 .input-group-text { background-color: #fff; border-color: #E8E8E8;} 
191			.input-group:hover .input-group-text, .input-group:hover .form-control.clp-search  
192		{ border-color: #888888!important;} 
193 .clp-search:focus { border-color: #D9D9D9; } 
194 .input-group .clp-search{ min-width: 210px;}	 
195	 
196 .search-card {background-color: #fff;border-color: rgba(0, 0, 0, 0.125);border-radius: 0.25rem; border-style: solid; 
197   border-width: 0.065rem; margin-bottom: 1.5rem;margin-top: -33px;position: absolute;word-wrap: break-word; right: 86px; 
198   min-width: 251px;  max-width: 251px; padding: 8px;z-index: 1;list-style-type:none;  max-height: 136px; overflow-y:auto;	  
199
200	.maxBoxScroll {overflow-y: auto; max-height: 100%;} 
201.clp-card::-webkit-scrollbar {width:5px; height: 89px; } 
202.clp-card::-webkit-scrollbar-track {background:#bcb7b7; border-radius:20px; } 
203.clp-card::-webkit-scrollbar-thumb {background:#DCDCDC; border-radius:29px;} 
204 
205 
206@media screen and (max-width: 1090px) { 
207    .clp-card { 
208        width: calc(25% - 20px);  
209
210
211@media screen and (max-width: 820px) { 
212    .clp-card { 
213        width: calc(35% - 50px); 
214
215
216@media screen and (max-width: 650px) { 
217    .clp-card { 
218        width: calc(50% - 30px);  
219
220
221@media screen and (max-width: 450px) { 
222    .clp-card { 
223        width: calc(90% - 65px);  
224
225
226</style>