i'm on 7.2.
i've been making board with configurationPid function of liferay, but it's not working what i think.
here's the thing
I set up three types of board to use preferences function of liferay.
From divCd information of preferences releated with board portlet keys, i can search boards specific datas.
But the problem is that when i shut down the server, datas diappear only for notice board! (divCd - 1 : NOTICE , divCd - 2 : FAQ, divCd -3 : QNA)
This phenomenon only happend to board table.
I didn't notice there's problem in my code because in dev server (local server) i've never seen this before.
This only happen in published server. When published server's down, datas of notice board disappear! (not happend to other table yet. :) ) Blow away for real!
I guess anyone in my company have never seen this (disappearing problem!).
So, because i used configurgationPid function to make reusable board
(Notice board, FAQ board, QNA board), configurationPid is quite suspicious for me. But I couldn't find this trouble shooting cases.
I'm gonna show you all my codes that used for this!
If you know any reasons why board data deleted, Please somebody help me.
Minor helps can alse be helpful for me!
flow
register board types
image => enter image description here
Board types can be defined here! and JSP file show theses
configuration.jsp
<%# page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%# page import="com.liferay.portal.kernel.util.Constants"%>
<%# page import="com.osp.board.constants.OSPBoardWebPortletKeys" %>
<%# page import="com.osp.board.constants.OSPBoardWebActionKeys" %>
<%# page import="java.util.Map"%>
<%# include file="../../init.jsp"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Board Configuration</title>
</head>
<body>
<liferay-portlet:actionURL portletConfiguration="<%= true %>" var="boardDivActionURL">
<liferay-portlet:param name="target" value="boardDiv"/>
</liferay-portlet:actionURL>
<liferay-portlet:actionURL portletConfiguration="<%= true %>" var="boardActionURL">
<liferay-portlet:param name="target" value="board"/>
</liferay-portlet:actionURL>
<liferay-portlet:actionURL portletConfiguration="<%= true %>" var="boardRemoveURL">
<liferay-portlet:param name="target" value="boardRemove"/>
<liferay-portlet:param name="targetedDivCd" value=""/>
</liferay-portlet:actionURL>
<%
long divCd = Long.parseLong(portletPreferences.getValue("divCd", "0"));
String originalBoardPlid = portletPreferences.getValue("originalBoardPlid", "");
boolean mainListYn = Boolean.parseBoolean(portletPreferences.getValue("mainListYn",""));
String originalBoardPortletName = portletPreferences.getValue("originalBoardPortletName", "");
%>
<c:set var="divCd" value="<%= divCd %>"/>
<c:set var="originalBoardPlid" value="<%= originalBoardPlid %>"/>
<c:set var="mainListYn" value="<%= mainListYn %>"/>
<c:set var="originalBoardPortletName" value="<%= originalBoardPortletName %>"/>
<div class="sheet sheet-lg panel-group panel-group-flush my-5">
<div class="panel">
<form action="${boardActionURL}" method="POST">
<aui:input name="<%= Constants.CMD %>" type="hidden" value="<%= Constants.UPDATE %>" />
<div class="panel-heading">
<a class="collapse-icon sheet-subtitle" data-toggle="collapse" href="#portletInfoContentBody" aria-expanded="false" aria-controls="portletInfoContentBody">
Portlet Information
<span class="collapse-icon-closed">
<svg class="lexicon-icon lexicon-icon-angle-right" focusable="false" role="presentation" viewBox="0 0 512 512">
<path class="lexicon-icon-outline" d="M396.394 255.607c-0.22-6.936-2.973-13.81-8.272-19.111l-227.221-227.221c-11.026-11.059-28.94-11.059-39.999 0-11.058 11.026-11.058 28.941 0 39.999l206.333 206.333c0 0-206.333 206.333-206.333 206.333-11.058 11.058-11.058 28.973 0 39.999 11.059 11.059 28.972 11.059 39.999 0l227.221-227.221c5.3-5.3 8.053-12.175 8.272-19.111z"></path>
</svg>
</span>
<span class="collapse-icon-open">
<svg class="lexicon-icon lexicon-icon-angle-down" focusable="false" role="presentation" viewBox="0 0 512 512">
<path class="lexicon-icon-outline" d="M256 384c6.936-0.22 13.81-2.973 19.111-8.272l227.221-227.221c11.058-11.026 11.058-28.941 0-39.999-11.026-11.058-28.94-11.058-39.999 0l-206.333 206.333c0 0-206.333-206.333-206.333-206.333-11.059-11.058-28.973-11.058-39.999 0-11.059 11.058-11.059 28.972 0 39.999l227.221 227.221c5.3 5.3 12.174 8.053 19.111 8.272z">
</path>
</svg>
</span>
</a>
</div>
<div id="portletInfoContentBody" class="panel-body collapse show">
<div class="alert alert-info">
PortletKey : ${portletKey}
<br/>
Plid : ${plid}
</div>
<c:choose>
<c:when test="${empty boardDivs}">
<aui:select name="divSort" label="board-config-property-name-divsort" helpMessage="board-config-property-explain-divsort" disabled="true">
</aui:select>
</c:when>
<c:otherwise>
<aui:select name="preferences--divCd--" label="board-config-property-name-divsort" helpMessage="board-config-property-explain-divsort">
<option value="0"> </option>
<c:forEach items="${boardDivs}" var="boardDiv">
<c:if test="${boardDiv.divCd eq divCd}">
<option value="${boardDiv.divCd}" selected="selected">${boardDiv.divName}</option>
</c:if>
<c:if test="${boardDiv.divCd ne divCd}">
<option value="${boardDiv.divCd}">${boardDiv.divName}</option>
</c:if>
</c:forEach>
</aui:select>
</c:otherwise>
</c:choose>
<div class="form-group">
<label>
<input type="hidden" name="<portlet:namespace/>preferences--mainListYn--" id="<portlet:namespace/>preferences--mainListYn--" value="${mainListYn}"/>
<input class="toggle-switch" type="checkbox" id="mainListYn" ${mainListYn ? 'checked="true"' : ''}>
<span class="toggle-switch-label">
<liferay-ui:message key="board-config-property-name-mainlistyn"/>
<liferay-ui:icon-help message="board-config-property-explain-mainlistyn"/>
</span>
<span aria-hidden="true" class="toggle-switch-bar">
<span class="toggle-switch-handle" data-label-off="no" data-label-on="yes">
</span>
</span>
</label>
</div>
<aui:input name="preferences--originalBoardPortletName--" label="board-config-property-name-originalboard-portletname" helpMessage="board-config-property-explain-portletname" value="${originalBoardPortletName}">
</aui:input>
<aui:input name="preferences--originalBoardPlid--" label="board-config-property-name-originalboard-plid" helpMessage="board-config-property-explain-plid" value="${originalBoardPlid}">
</aui:input>
<div class="d-flex justify-content-end">
<button type="submit" class="btn btn-primary"><liferay-ui:message key="save"/></button>
</div>
</div>
</form>
</div>
</div>
<div class="sheet sheet-lg panel-group panel-group-flush my-5">
<div class="panel">
<form action="${boardDivActionURL}" method="POST" id="boardTypeList">
<div class="panel-heading">
<a class="collapse-icon sheet-subtitle" data-toggle="collapse" href="#boardDivContentBody" aria-expanded="false" aria-controls="boardDivContentBody">
<liferay-ui:message key="board-config-property-boarddiv-title"/>
<span class="collapse-icon-closed">
<svg class="lexicon-icon lexicon-icon-angle-right" focusable="false" role="presentation" viewBox="0 0 512 512">
<path class="lexicon-icon-outline" d="M396.394 255.607c-0.22-6.936-2.973-13.81-8.272-19.111l-227.221-227.221c-11.026-11.059-28.94-11.059-39.999 0-11.058 11.026-11.058 28.941 0 39.999l206.333 206.333c0 0-206.333 206.333-206.333 206.333-11.058 11.058-11.058 28.973 0 39.999 11.059 11.059 28.972 11.059 39.999 0l227.221-227.221c5.3-5.3 8.053-12.175 8.272-19.111z"></path>
</svg>
</span>
<span class="collapse-icon-open">
<svg class="lexicon-icon lexicon-icon-angle-down" focusable="false" role="presentation" viewBox="0 0 512 512">
<path class="lexicon-icon-outline" d="M256 384c6.936-0.22 13.81-2.973 19.111-8.272l227.221-227.221c11.058-11.026 11.058-28.941 0-39.999-11.026-11.058-28.94-11.058-39.999 0l-206.333 206.333c0 0-206.333-206.333-206.333-206.333-11.059-11.058-28.973-11.058-39.999 0-11.059 11.058-11.059 28.972 0 39.999l227.221 227.221c5.3 5.3 12.174 8.053 19.111 8.272z">
</path>
</svg>
</span>
</a>
</div>
<div id="boardDivContentBody" class="panel-body collapse show">
<div class="form-group">
<div class="table-responsive-md">
<table class="table table-bordered">
<!-- <colgroup>
<col width="5%">
<col width="16.5%">
<col width="25.5%">
<col width="10%">
<col width="23%">
<col width="6%">
<col width="8%">
</colgroup> -->
<thead>
<tr>
<th scope="col" class="text-center"><liferay-ui:message key="table-index"/></th>
<c:forEach items="${locales}" var="locale">
<th scope="col" class="text-center">Title(${locale})</th>
</c:forEach>
<th scope="col" class="text-center"><liferay-ui:message key="board-config-property-boarddiv-column-content"/></th>
<th scope="col" class="text-center"><liferay-ui:message key="board-config-property-boarddiv-column-name"/></th>
<th scope="col" class="text-center"><liferay-ui:message key="board-config-property-boarddiv-column-fileuse"/></th>
<th scope="col" class="text-center"><liferay-ui:message key="board-config-property-boarddiv-column-popupuse"/></th>
<th scope="col" class="text-center"><liferay-ui:message key="board-config-property-boarddiv-column-replyuse"/></th>
<th scope="col" class="text-center"></th>
</tr>
</thead>
<tbody data-entity="boardDiv">
<c:choose>
<c:when test="${empty boardDivs}">
<tr data-nodata="true">
<td class="text-center text-danger" colspan="8">
<liferay-ui:message key="board-config-property-boarddiv-result-noboarddiv"/>
</td>
</tr>
</c:when>
<c:otherwise>
<c:forEach items="${boardDivs}" var="boardDiv" varStatus="vs">
<tr>
<input type="hidden" name="<portlet:namespace/>idx" value="${vs.count}"/>
<input type="hidden" name="<portlet:namespace/>divCd" value="${boardDiv.divCd}"/>
<td scope="col" class="text-center">${vs.count}</td>
<c:forEach items="${locales}" var="locale">
<c:set var="titleKey" value="title_${locale}"/>
<td scope="col" class="text-center">
<input type="text" class="form-control" name="<portlet:namespace/>title_${locale}_${vs.count}" value="${boardDiv[titleKey]}" maxlength="30"/>
</td>
</c:forEach>
<td scope="col" class="text-center">
<input type="text" class="form-control" name="<portlet:namespace/>content_${vs.count}" value="${boardDiv.content}" maxlength="30"/>
</td>
<td scope="col" class="text-center">
<input type="text" class="form-control" name="<portlet:namespace/>divName_${vs.count}" value="${boardDiv.divName}" maxlength="30"/>
</td>
<td scope="col" class="text-center">
<input type="checkbox" name="<portlet:namespace/>fileUploadUseYn_${vs.count}" ${boardDiv.fileUploadUseYn ? 'checked="true"' : ''}/>
</td>
<td scope="col" class="text-center">
<input type="checkbox" name="<portlet:namespace/>popupYn_${vs.count}" ${boardDiv.popupYn ? 'checked="true"' : ''}/>
</td>
<td scope="col" class="text-center">
<input type="checkbox" name="<portlet:namespace/>replyYn_${vs.count}" ${boardDiv.replyYn ? 'checked="true"' : ''}/>
</td>
<td scope="col" class="text-center">
<button class="btn btn-default" type="button" data-target-entity="remove" data-event="remove" data-div-cd="${boardDiv.divCd}">
<i class="icon-trash"></i>
</button>
</td>
</tr>
</c:forEach>
</c:otherwise>
</c:choose>
</tbody>
</table>
</div>
</div>
<div class="d-flex d-flex justify-content-between">
<button type="button" class="btn btn-outline-dark" data-target-entity="boardDiv">
<i class="icon-plus"></i>
Board Type
</button>
<button type="submit" class="btn btn-primary"><liferay-ui:message key="save"/></button>
</div>
</div>
</form>
</div>
</div>
</body>
</html>
<script type="text/javascript">
$(function(){
$('#mainListYn').on('change', function(){
$('#<portlet:namespace/>preferences--mainListYn--').val($(this).prop('checked'));
});
$(document).on('click','[data-target-entity]', function(){
var target = $('[data-entity="'+$(this).data('targetEntity')+'"]');
if($(target).find('[data-nodata="true"]').length > 0){
$(target).empty();
}
var targetType = $(this).data("targetEntity") || "";
if(targetType == "remove"){
var targetedDivCd = $(this).data('divCd') || '';
if(targetedDivCd != ""){
$.ospConfirm({
modalDialogClass : 'modal-md',
title : '<liferay-ui:message key="board-app-delete-modal-title"/>',
confirmText : '<liferay-ui:message key="board-app-notice-delete-modal-btn"/>',
body : '<liferay-ui:message key="board-app-delete-modal-body"/>',
closeText : '<liferay-ui:message key="board-app-delete-cancel"/>',
onSubmit : function(result){
if(result){
var actionURL = "${boardRemoveURL}";
actionURL +="&_com_liferay_portlet_configuration_web_portlet_PortletConfigurationPortlet_targetedDivCd=" + targetedDivCd;
window.location = actionURL.toString();
}
}
});
}else{
$(this).closest("tr").remove();
}
return;
}
var idx = $(target).find('tr').length + 1;
if('content' in document.createElement('template')){
var tmpl = document.querySelector('#boardDivTmpl');
var clone = document.importNode(tmpl.content, true);
$(clone).find("tr").prepend(
$('<input/>').attr({
type : 'hidden',
name : '<portlet:namespace/>idx',
value : idx
}),
$('<input/>').attr({
type : 'hidden',
name : '<portlet:namespace/>divCd',
value : 0
})
);
var tds = clone.querySelectorAll("td");
tds.forEach( (td, i) => {
if(i == 0){
$(td).text(idx);
}else{
if($(tds).eq(i).find('input').length > 0){
var input = $(td).find('input:eq(0)');
var bName = $(input).attr('name');
var aName = bName.replace('_idx', '_'+idx);
$(tds).eq(i).find('input:eq(0)').attr('name', aName);
}
}
});
$(target).append(clone);
} else{
var input = $('<input/>').addClass('form-control'),
checkbox = $('<input/>').attr('type', 'checkbox'),
appendTd = $('<td/>').addClass('text-center');
$('<tr/>').append(
$('<input/>').attr({
type : 'hidden',
name : '<portlet:namespace/>idx',
value : idx
}),
$(appendTd).clone()
.text(idx),
$(appendTd).clone()
.append(
$(input).clone().attr('name', '<portlet:namespace/>title_ko_KR_'+idx)
),
$(appendTd).clone()
.append(
$(input).clone().attr('name', '<portlet:namespace/>title_en_US_'+idx)
),
$(appendTd).clone()
.append(
$(input).clone().attr('name', '<portlet:namespace/>content_'+idx)
),
$(appendTd).clone()
.append(
$(input).clone().attr('name', '<portlet:namespace/>divName_'+idx)
),
$(appendTd).clone()
.append(
$(checkbox).clone().attr('name', '<portlet:namespace/>fileUploadUseYn_'+idx)
),
$(appendTd).clone()
.append(
$(checkbox).clone().attr('name', '<portlet:namespace/>popupYn_'+idx)
),
$(appendTd).clone()
.append(
$(checkbox).clone().attr('name', '<portlet:namespace/>replyYn_'+idx)
)
).appendTo(target);
}
});
});
</script>
<template id="boardDivTmpl">
<tr>
<td scope="col" class="text-center"></td>
<c:forEach items="${locales}" var="locale">
<td scope="col" class="text-center">
<input type="text" class="form-control" name="<portlet:namespace/>title_${locale}_idx"/>
</td>
</c:forEach>
<td scope="col" class="text-center">
<input type="text" class="form-control" name="<portlet:namespace/>content_idx"/>
</td>
<td scope="col" class="text-center">
<input type="text" class="form-control" name="<portlet:namespace/>divName_idx"/>
</td>
<td scope="col" class="text-center">
<input type="checkbox" name="<portlet:namespace/>fileUploadUseYn_idx"/>
</td>
<td scope="col" class="text-center">
<input type="checkbox" name="<portlet:namespace/>popupYn_idx"/>
</td>
<td scope="col" class="text-center">
<input type="checkbox" name="<portlet:namespace/>replyYn_idx"/>
</td>
<td>
<button class="btn btn-default" type="button" data-target-entity="remove">
<i class="icon-trash"></i>
</button>
</td>
</tr>
</template>
If you save for delete, you can see if they exists on my table!
image => enter image description here
but, It was not simple if i need to use OSP_BoardDiv.
In main page, I must know exact plid to get to the right board type.
For this, I should set plid, divCd before you main page for preview of
notice board. And i set it on html tags.
image => enter image description here
If board types are set, i can read information from BoardRender.
And the next thing is all the same. Controlling data with action,
render, resources ... but i can't find any problem on my codes!
I must get plId infos to nevigate user to get to the right board. So, I access to xml datas of the PortletPreferences table. If portletId is same with board portlet and divCd is same, get datas!
BoardRender.java
package com.osp.board.web.board.command;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.PortletPreferences;
import com.liferay.portal.kernel.portlet.bridges.mvc.MVCRenderCommand;
import com.liferay.portal.kernel.service.PortletPreferencesLocalServiceUtil;
import com.liferay.portal.kernel.servlet.SessionErrors;
import com.liferay.portal.kernel.servlet.SessionMessages;
import com.liferay.portal.kernel.theme.ThemeDisplay;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.LocaleUtil;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.kernel.util.PortalUtil;
import com.liferay.portal.kernel.util.WebKeys;
import com.osp.board.constants.ConstantsPagePath;
import com.osp.board.constants.OSPBoardWebPortletKeys;
import com.osp.board.model.Board;
import com.osp.board.model.BoardDiv;
import com.osp.board.service.BoardDivLocalServiceUtil;
import com.osp.board.service.BoardLocalServiceUtil;
import com.osp.constants.CustomRoleConstants;
import com.osp.constants.MessageConstants;
import com.osp.constants.SiteNameConstants;
import com.osp.search.constants.OSPSearchPortletKeys;
import com.osp.util.CustomUtil;
import com.osp.util.OSPPropertiesUtil;
import com.osp.util.OSPUsersUtil;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.portlet.PortletException;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.osgi.service.component.annotations.Component;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
#Component(
immediate = true,
property = {
"javax.portlet.name=" + OSPBoardWebPortletKeys.BOARD_PORTLET_KEY,
"mvc.command.name=/",
"javax.portlet.version=3.0"
},
service = MVCRenderCommand.class
)
public class BoardRender implements MVCRenderCommand {
private static final Log _log = LogFactoryUtil.getLog(BoardRender.class);
#Override
public String render(RenderRequest renderRequest, RenderResponse renderResponse) throws PortletException {
ThemeDisplay themeDisplay = (ThemeDisplay) renderRequest.getAttribute(WebKeys.THEME_DISPLAY);
String isMainPage = renderRequest.getPreferences().getValue("mainListYn", "false");
String jspPage = ConstantsPagePath.OSP_BOARD_LIST;
String escapeTag = "<(/)?([a-zA-Z]*)(\\\\s[a-zA-Z]*=[^>]*)?(\\\\s)*(/)?>";
long divCd = Long.parseLong(renderRequest.getPreferences().getValue("divCd", "0"));
try {
if(divCd > 0) {
BoardDiv boardDiv = BoardDivLocalServiceUtil.getBoardDiv(divCd);
Map<String, Object> boardDivMap = new HashMap<String, Object>();
boardDivMap.put("title", boardDiv.getTitle(themeDisplay.getLanguageId()));
// permission check start.
String divName = GetterUtil.getString(boardDiv.getDivName(), "FAQ").toUpperCase();
boolean permission = false;
if(isMainPage.equals("true")) {// write only portal, site admins.
List<PortletPreferences> searchPreferences = null;
String searchNamespace = "";
String siteName = CustomUtil.strNull(OSPPropertiesUtil.getPortalSiteName(),"1");
renderRequest.setAttribute("siteName", siteName);
if(siteName.equals(SiteNameConstants.BIO)) {
searchPreferences = PortletPreferencesLocalServiceUtil.getPortletPreferences().stream().filter(pp -> pp.getPortletId().equals(OSPSearchPortletKeys.TOTAL_LIST_SEARCH_PORTLET_KEY)).collect(Collectors.toList());
searchNamespace = PortalUtil.getPortletNamespace(OSPSearchPortletKeys.TOTAL_LIST_SEARCH_PORTLET_KEY);
}else {
searchPreferences = PortletPreferencesLocalServiceUtil.getPortletPreferences().stream().filter(pp -> pp.getPortletId().equals(OSPSearchPortletKeys.MATERIAL_LIST_SEARCH_PORTLET_KEY)).collect(Collectors.toList());
searchNamespace = PortalUtil.getPortletNamespace(OSPSearchPortletKeys.MATERIAL_LIST_SEARCH_PORTLET_KEY);
}
if(searchPreferences != null) {
long searchPlid = searchPreferences.get(0).getPlid();
renderRequest.setAttribute("searchPlid", searchPlid);
renderRequest.setAttribute("searchNamespace", searchNamespace);
}
List<PortletPreferences> boardPrefereneces = PortletPreferencesLocalServiceUtil.getPortletPreferences().stream().filter(pp -> pp.getPortletId().equals(OSPBoardWebPortletKeys.BOARD_PORTLET_KEY)).collect(Collectors.toList());
Map<String, Map<String, Object>> resultMap = new HashMap<String, Map<String,Object>>();
List<BoardDiv> boardTypeList = BoardDivLocalServiceUtil.getBoardDivListWithBoardName();
for(PortletPreferences pp : boardPrefereneces) {
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
InputSource is = new InputSource();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
is.setCharacterStream(new StringReader(pp.getPreferences()));
Document document = docBuilder.parse(is);
document.getDocumentElement().normalize();
if(document.getElementsByTagName("value").getLength() > 0 ) {
NodeList valueList = document.getElementsByTagName("value");
String nodeValue = "";
for(BoardDiv bdiv : boardTypeList) {
for(int i = 0; valueList.getLength() > i; i++) {
Node valueNode = valueList.item(i);
nodeValue = valueNode.getTextContent();
if(String.valueOf(bdiv.getDivCd()).equals(nodeValue)) {
Map <String, Object> dataMap = new HashMap<>();
dataMap.put("plid",pp.getPlid());
dataMap.put("portletId",pp.getPortletId());
dataMap.put("divCd", nodeValue);
resultMap.put(bdiv.getContent().toUpperCase(), dataMap);
break;
}
}
}
}
}
List<Board> boardListForMainNotice = new ArrayList<Board>();
List<Board> boardListForMainFaq = new ArrayList<Board>();
for(BoardDiv bdiv : boardTypeList) {
if("NOTICE".equals(bdiv.getContent().toUpperCase())) // notice
boardListForMainNotice = BoardLocalServiceUtil.getBoardListByDivcdSiteGroupIdsForMain(bdiv.getDivCd(), themeDisplay.getScopeGroupId(), 0, 3, themeDisplay.getLanguageId());
if("FAQ".equals(bdiv.getContent().toUpperCase())) // faq
boardListForMainFaq = BoardLocalServiceUtil.getBoardListByDivcdSiteGroupIdsForMain(bdiv.getDivCd(), themeDisplay.getScopeGroupId(), 0, 4, themeDisplay.getLanguageId());
}
for(Board board : boardListForMainNotice) {
board.setTitle(board.getTitle(LocaleUtil.KOREA));
board.setCreateDate(board.getCreateDate());
board.setContent(board.getContent(LocaleUtil.KOREA).replaceAll(escapeTag, ""));
}
for(Board board : boardListForMainFaq){
board.setTitle(board.getTitle(LocaleUtil.KOREA));
board.setCreateDate(board.getCreateDate());
board.setContent(board.getContent(LocaleUtil.KOREA).replaceAll(escapeTag, "").replaceAll(" ", "<br>").replaceAll("<br>", ""));
}
renderRequest.setAttribute("boardInfos", resultMap);
renderRequest.setAttribute("boardListForMainNotice", boardListForMainNotice);
renderRequest.setAttribute("boardListForMainFaq", boardListForMainFaq);
jspPage = ConstantsPagePath.OSP_MAIN_BOARD_LIST;
}else if("QNA".equals(divName)) {// admins or writer.
permission = themeDisplay.getPermissionChecker().isSignedIn();
}else if("FAQ".equals(divName)||divName.equals("NOTICE")) {
permission = OSPUsersUtil.isRegularRole(themeDisplay.getUser(), CustomRoleConstants.ADMINISTRATOR);
if(!permission) permission = OSPUsersUtil.isSiteRole(themeDisplay.getUser(), themeDisplay.getScopeGroupId(), CustomRoleConstants.SITE_ADMINISTRATOR);
}else {
_log.debug("##### DivName '"+divName+"' is not supported yet.");
_log.debug("##### Check role like FAQ(Write only admins.).");
permission = OSPUsersUtil.isRegularRole(themeDisplay.getUser(), CustomRoleConstants.ADMINISTRATOR);
if(!permission) permission = OSPUsersUtil.isSiteRole(themeDisplay.getUser(), themeDisplay.getScopeGroupId(), CustomRoleConstants.SITE_ADMINISTRATOR);
}
renderRequest.setAttribute("permission", permission);
// permission check end.
renderRequest.setAttribute("boardDiv", boardDivMap);
}else {
SessionErrors.add(renderRequest, MessageConstants.SEARCH_ERROR);
}
} catch (Exception e) {
_log.error(e);
jspPage = ConstantsPagePath.OSP_MAIN_BOARD_LIST;
renderRequest.setAttribute("permission", false);
SessionErrors.add(renderRequest, MessageConstants.SEARCH_ERROR);
}
// session message print.
String msgType = ParamUtil.getString(renderRequest, "msgType", "");
if(msgType.equals("error")) {
SessionErrors.add(renderRequest, ParamUtil.getString(renderRequest, "ssMsg", ""));
}else if(!msgType.equals("")) {
SessionMessages.add(renderRequest, ParamUtil.getString(renderRequest, "ssMsg", ""));
}
SessionMessages.add(renderRequest, PortalUtil.getPortletId(renderRequest) + SessionMessages.KEY_SUFFIX_HIDE_DEFAULT_ERROR_MESSAGE);
return jspPage;
}
public static void main(String[] args) {
}
}
BoardConfig.java
package com.osp.board.web.board.config;
import com.liferay.portal.configuration.metatype.annotations.ExtendedObjectClassDefinition;
import com.osp.board.constants.OSPBoardWebPortletKeys;
import aQute.bnd.annotation.metatype.Meta;
#ExtendedObjectClassDefinition(
category = "board",
scope = ExtendedObjectClassDefinition.Scope.SYSTEM
)
#Meta.OCD(
id = OSPBoardWebPortletKeys.BOARD_CONFIG_PORTLET_KEY
)
public interface BoardConfig {
}
I'm a beginner in Laravel 7. I am trying to create a checkout form when purchasing items. The problem is whenever I try to delete the first item the 'The DELETE method is not supported for this route. Supported methods: GET, HEAD, POST.' shows up. However, I am able to delete the following items under it that I put into the checkout form.
This is my CheckoutController
public function destroy($id)
{
Temp_order::where('id',$id)->delete();
return redirect('checkout')->with('success','Product deleted successfully');
}
And this is the code for the table
<tbody>
#forelse ($order as $item)
<tr>
<td id="item_code">{{ $item->item_code }}</td>
<td class="cart_product_img" id="image">
<img src="" alt="Unavailable" style="width: 70px; height:70px"></img>
</td>
<td id="item_name">
{{ $item->item_name }}
</td>
<td id="price">
₱ {{ number_format($item->price, 2) }}
</td>
<td class="qty" id="qty">
<div class="qty-btn d-flex">
<div class="quantity">
<input type="number" class="qty-text" id="qty" step="1" min="1" max="300" name="quantity" value="{{ $item->quantity }}">
</div>
</div>
</td>
<td id="subtotal">
₱ {{ number_format($item->subtotal, 2) }}
</td>
<td>
<form action="{{ route('checkout.destroy', $item->id) }}" method="post">
#csrf
#method('DELETE')
<button type="submit" class="btn btn-danger btn-sm">Remove</button>
</form>
</td>
</tr>
#empty
<tr>
<td>
<p> NO ITEMS IN CART </p>
</td>
</tr>
#endforelse
</tbody>
And this is my route
Route::get('/', function () {
return view('auth.login');
});
Auth::routes();
Route::get('/home', 'HomeController#index')->name('home');
Route::resource('ordering', 'OrderingController')->middleware('auth');
Route::resource('inventory', 'InventoryController')->middleware('auth');
Route::resource('checkout', 'CheckoutController')->middleware('auth');
Can you help me masters?
Try to update CheckoutController
public function destroy(Temp_order $item)
{
$item->delete();
return redirect('checkout')->with('success','Product deleted successfully');
}
I have a form that uses jBox to provide additional info for some fields in tooltips. The text that is displayed depends on the value of the closest select-tag. jBox is executed on PageLoad (I create a single jBox which uses data-attributes to get title and content) and I then update the data-attributes in response to the change-event on the select-control.
Unfortunately that does not work, the tooltip stays with the initial value.
I have a cut-down repro with tooltip that illustrates the behaviour of not being updated (alertis used to show actual values of data-attributes after a change-event)
$(function() {
$("[data-jbox-content]").jBox("Tooltip", {
theme: "TooltipDark",
id: "jBoxTooltip",
getTitle: "data-jbox-title",
getContent: "data-jbox-content"
});
});
<link href="https://cdn.jsdelivr.net/gh/StephanWagner/jBox#v1.0.5/dist/jBox.all.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/StephanWagner/jBox#v1.0.5/dist/jBox.all.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css" rel="stylesheet"/>
<body>
<table>
<tbody>
<tr>
<th>Variable</th>
<th colspan="2">Type</th>
<th>Description</th>
</tr>
<tr>
<td><label for="dt1">Car</label></td>
<td><select id="dtCar" class="form-control select2 font-fas" name="dtCar" onchange="$('#infoCar').data('jbox-title','blabla');$('#infoCar').data('jbox-content','dummy');alert($('#infoCar').data('jbox-title')+' / ' + $('#infoCar').data('jbox-content'))">
<option>Key</option>
<option selected="selected">Boolean</option>
<option>Ordinal</option>
<option>Nominal</option>
<option>Interval</option>
<option>Ratio</option>
</select>
</td>
<td><span id="infoCar" data-jbox-content="This field can have one of two values: On or Off, Yes or No, 1 or 0." data-jbox-title="Description of the Boolean Scale">
<i class="fas fa-info-circle"></i></span></td>
<td><input id="inCar" class="form-control" name="inCar" type="text" value="Do you own a car?"></td>
</tr>
<tr>
<td><label for="dt2">Age</label></td>
<td><select id="dtHouse" class="form-control select2 font-fas" name="dtAge" onchange="$('#infoAge').data('jbox-title','blabla');$('#infoAge').data('jbox-content','dummy');alert($('#infoAge').data('jbox-title')+' / ' + $('#infoAge').data('jbox-content'))">
<option>Key</option>
<option>Boolean</option>
<option>Ordinal</option>
<option>Nominal</option>
<option selected="selected">Interval</option>
<option>Ratio</option>
</select>
</td>
<td><span id="infoAge" data-jbox-content="This field can values from a defined interval, i.e. 0..200" data-jbox-title="Description of the Interval Scale">
<i class="fas fa-info-circle"></i></span></td>
<td><input id="inHouse" class="form-control" name="inAge" type="text" value="How old are you?"></td>
</tr>
</tbody>
</table>
</body>
There is a common misunderstanding of how jQuery uses .data() and .attr() methods.
.data() adds some internal data to the element itself and will not set an attribute.
To set a data-xxx attribute you need to use .attr(). See more here: https://api.jquery.com/attr/
Also, check out updated snippet:
$(function() {
$("[data-jbox-content]").jBox("Tooltip", {
theme: "TooltipDark",
id: "jBoxTooltip",
getTitle: "data-jbox-title",
getContent: "data-jbox-content"
});
});
<link href="https://cdn.jsdelivr.net/gh/StephanWagner/jBox#v1.0.5/dist/jBox.all.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/gh/StephanWagner/jBox#v1.0.5/dist/jBox.all.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css" rel="stylesheet"/>
<body>
<table>
<tbody>
<tr>
<th>Variable</th>
<th colspan="2">Type</th>
<th>Description</th>
</tr>
<tr>
<td><label for="dt1">Car</label></td>
<td><select id="dtCar" class="form-control select2 font-fas" name="dtCar" onchange="$('#infoCar').attr('data-jbox-title','blabla');$('#infoCar').attr('data-jbox-content','dummy');">
<option>Key</option>
<option selected="selected">Boolean</option>
<option>Ordinal</option>
<option>Nominal</option>
<option>Interval</option>
<option>Ratio</option>
</select>
</td>
<td><span id="infoCar" data-jbox-content="This field can have one of two values: On or Off, Yes or No, 1 or 0." data-jbox-title="Description of the Boolean Scale">
<i class="fas fa-info-circle"></i></span></td>
<td><input id="inCar" class="form-control" name="inCar" type="text" value="Do you own a car?"></td>
</tr>
<tr>
<td><label for="dt2">Age</label></td>
<td><select id="dtHouse" class="form-control select2 font-fas" name="dtAge" onchange="$('#infoAge').attr('data-jbox-title','blabla');$('#infoAge').attr('data-jbox-content','dummy');">
<option>Key</option>
<option>Boolean</option>
<option>Ordinal</option>
<option>Nominal</option>
<option selected="selected">Interval</option>
<option>Ratio</option>
</select>
</td>
<td><span id="infoAge" data-jbox-content="This field can values from a defined interval, i.e. 0..200" data-jbox-title="Description of the Interval Scale">
<i class="fas fa-info-circle"></i></span></td>
<td><input id="inHouse" class="form-control" name="inAge" type="text" value="How old are you?"></td>
</tr>
</tbody>
</table>
</body>
Here is my module.
module.exports = function (requestUser) {
let content = `
<div id="cpl">
<table id="currentpatientslists">
</table>
</div>
<div id="rp">
<h1>Requested Patients</h1>
</div>
<hr>
<div id="note" >Currently no patients</div>
<div id="rpl">
<table id="requestedpatientslists">
<tr>
<td width="30%"></td>
<td width="30%" class="right"><button>Accept</button></td>
<td width="30%" class="left"><button>Reject</button></td>
</tr>
</table>
</div>`;
return render(content);
}
In the requestedpatientslists table , I want to loop the data in the table row coming from requestUser which is an array. I want to loop it until requestUser.length. How can I do that?
You just need to loop over the users and create the rows for them first
module.exports = function(requestUser) {
// I'm guessing that the user has normal properties like name, etc?
const tableRows = requestUser.map(
user => `
<tr>
<td width="30%">${user.name}</td>
<td width="30%" class="right"><button>Accept</button></td>
<td width="30%" class="left"><button>Reject</button></td>
</tr>
`,
);
const content = `
<div id="cpl">
<table id="currentpatientslists">
</table>
</div>
<div id="rp">
<h1>Requested Patients</h1>
</div>
<hr>
<div id="note" >Currently no patients</div>
<div id="rpl">
<table id="requestedpatientslists">
${tableRows.join('\n')}
</table>
</div>`;
return render(content);
};
i have retrieved a list of abjects from firebase onto my ejs file: and i am retrieving them in this manner:
<form id="eventform" method="post" action="/dasha">
<%Object.keys(notes).forEach(function(key){%>
<tbody id="event" name="event">
<tr>
<td>1</td>
<input type="hidden" id="categ" name="categ" value="<%=notes[key].event %>">
<td id="evname" name="evname"><%=notes[key].event %></td>
</form>
<td><%=notes[key].location %></td>
<td><%=notes[key].codes %></td>
<td><%=notes[key].date %></td>
</tr>
<% }) %>
</tbody>
I am however trying to implement an Onclick for so that when an item is clicked on it carries its info to the next page: I have tried to store it in aninput field like:
**<input type="hidden" id="categ" name="categ" value="<%=notes[key].event %>">**
But i just cant get the individual item it pulls the whole array when i check for the value.Any help
Here is the sample data
Then i use jquery to submit:
$(document).ready(function () {
$("#event").click(function(){
var en = $("#evname").val();
$("#categ").val(en);
$("#eventform").submit();
});
});
Here is the rendered htmlsource and images /:
<tbody id="eventName" class="eventName" style="cursor: crosshair;" name="eventName">
<%Object.keys(notes).forEach(function(key,idx){%>
<tr>
<td id="tid" name="tid" class="tid" ><%= idx %></td>
<form name="eventForm-<%= idx %>" class="eventForm" method="post" action="/dasha">
<input type="hidden" id="categ-<%= idx %>" name="categ" class="categ" value="<%=notes[key].event %>">
<input type="hidden" id="idd" name="idd" class="idd" value="<%= idx %>">
</form>
<td id="evname-<%= idx %>" name="evname-<%= idx %>"><%=notes[key].event %></td>
<td id="elocation" name="elocation"><%=notes[key].location %></td>
<td id="ecodes" name="ecodes"><%=notes[key].code %></td>
<td id="edate" name="edate"><%=notes[key].date %></td>
</tr>
<% }) %>
</tbody>
Here is the rendered html from the browser:
<tbody id="eventName" class="eventName" style="cursor: crosshair;" name="eventName">
<tr>
<td id="tid" name="tid" class="tid">0</td>
<form name="eventForm-0" class="eventForm" method="post" action="/dasha"></form>
<input type="hidden" id="categ-0" name="categ" class="categ" value="zuri.png">
<input type="hidden" id="idd" name="idd" class="idd" value="0">
<td id="evname-0" name="evname-0">zuri.png</td>
<td id="elocation" name="elocation">zuri.png</td>
<td id="ecodes" name="ecodes"></td>
<td id="edate" name="edate">-LZfAvzWGudUK78TGtT_</td>
</tr>
<tr>
<td id="tid" name="tid" class="tid">1</td>
<form name="eventForm-1" class="eventForm" method="post" action="/dasha"></form>
<input type="hidden" id="categ-1" name="categ" class="categ" value="Africa Tourism Technology and Innovation Awards">
<input type="hidden" id="idd" name="idd" class="idd" value="1">
<td id="evname-1" name="evname-1">Africa Tourism Technology and Innovation Awards</td>
<td id="elocation" name="elocation">USIU – Africa</td>
<td id="ecodes" name="ecodes">AA24VI</td>
<td id="edate" name="edate">25th – 26th April, 2019</td>
</tr>
<tr>
<td id="tid" name="tid" class="tid">2</td>
<form name="eventForm-2" class="eventForm" method="post" action="/dasha"></form>
<input type="hidden" id="categ-2" name="categ" class="categ" value="2nd Annual Global M I C E Summit">
<input type="hidden" id="idd" name="idd" class="idd" value="2">
<td id="evname-2" name="evname-2">2nd Annual Global M I C E Summit</td>
<td id="elocation" name="elocation">Trademark Hotel</td>
<td id="ecodes" name="ecodes">RT79XV</td>
<td id="edate" name="edate">11th – 13th September, 2019</td>
</tr>
</tbody>
You have a number of issues with your code, and despite trying to highlight them in comments there isn't enough space, hence this 'incomplete' answer
For starters you are opening a form tag before your forEach loop. You then close it during the first loop. So on your subsequent iterations there isn't a form to find.
Secondly, you have reused the same ID during the loop, which you should not do as it will generate multiple items with the same ID if you have multiple Objects you're looping through. If you have 2 elements with an ID of 'foo', using multiple of the same ID will lead to unintended consequences , each ID should be unique.
Thirdly you don't have a <table> tag around your tbody, some browsers therefore strip the tbody so you're click event will never fire. Also your rows are within a <tr> element so you should attach your click handler to this.
<form id="eventform" method="post" action="/dasha">
<%Object.keys(notes).forEach(function(key){%>
<tbody id="event" name="event">
<tr>
<td>1</td>
<input type="hidden" id="categ" name="categ" value="<%=notes[key].event %>">
<td id="evname" name="evname"><%=notes[key].event %></td>
</form> // YOU'RE CLOSING YOUR FORM HERE INSIDE THE LOOP ITERATION
<td><%=notes[key].location %></td>
<td><%=notes[key].codes %></td>
<td><%=notes[key].date %></td>
</tr>
<% }) %>
</tbody>
Now this isn't tested, and as I don't know the complete layout of your page it's a bit of a stab in the dark, but you could try something like the following and see if you have any luck
<%Object.keys(notes).forEach(function(key,idx){%>
<table>
<tbody id="event-<%= idx =>" name="event" class="eventName">
<tr class="row">
<td>1</td>
<form name="eventForm-<%= idx %>" class="eventForm" method="post" action="/dasha">
<input type="hidden" id="categ-<%= idx %>" name="categ" class="categ" value="<%=notes[key].event %>">
</form>
<td id="evname-<%= idx %>" name="evname-<%= idx %>"><%=notes[key].event %></td>
<td><%=notes[key].location %></td>
<td><%=notes[key].codes %></td>
<td><%=notes[key].date %></td>
</tr>
<% }) %>
</tbody>
</table>
And a click handler similar to
$(document).ready(function () {
$(".row").click(function(ev){
let form = ev.currentTarget.querySelector('form');
form.submit()
});
A simpler version using vanilla JS can be found here https://jsfiddle.net/xvag0mj2/