When we add static data in angular datatable all things work fine, but when we load the data table from an API, the pagination, search, and sorting don't work. And it show's "No data available in table", but data is present in the table, also attaching the images.
Click me to view img
Here is the HTML Code
<table datatable [dtOptions]="dtOptions" class="datatable-init nowrap nk-tb-list nk-tb-ulist">
<thead>
<tr class="nk-tb-item nk-tb-head">
<th class="nk-tb-col nk-tb-col-check">
<div class="custom-control custom-control-sm custom-checkbox notext">
<input type="checkbox" class="custom-control-input" id="uid" />
<label class="custom-control-label" for="uid"></label>
</div>
</th>
<th class="nk-tb-col"><span class="sub-text">Customer Name</span></th>
<th class="nk-tb-col tb-col-mb">
<span class="sub-text">Phone Number</span>
</th>
<th class="nk-tb-col tb-col-md">
<span class="sub-text">CNIC</span>
</th>
<th class="nk-tb-col tb-col-lg">
<span class="sub-text">Joining Date</span>
</th>
<th class="nk-tb-col tb-col-lg">
<span class="sub-text">Expiry Date</span>
</th>
<th class="nk-tb-col tb-col-lg">
<span class="sub-text">Status</span>
</th>
<th class="nk-tb-col nk-tb-col-tools text-end"></th>
</tr>
</thead>
<tbody >
<tr class="nk-tb-item" *ngFor="let user of allUsers">
<td class="nk-tb-col nk-tb-col-check">
<div class="custom-control custom-control-sm custom-checkbox notext">
<input type="checkbox" class="custom-control-input" id="uid1" />
<label class="custom-control-label" for="uid1"></label>
</div>
</td>
<td class="nk-tb-col">
<span>{{user.customerName}}</span>
</td>
<td class="nk-tb-col tb-col-md">
<span>{{user.phoneNumber}}</span>
</td>
<td class="nk-tb-col tb-col-lg">
<span>{{user.CNIC_Number}}</span>
</td>
<td class="nk-tb-col tb-col-lg">
<span class="badge bg-secondary">{{user.Joining_Date}}</span>
</td>
<td class="nk-tb-col tb-col-md">
<span class="badge bg-danger">{{user.Expiry_Date}}</span>
</td>
<td class="nk-tb-col tb-col-md">
<span class="badge bg-success">Active</span>
</td>
<td class="nk-tb-col nk-tb-col-tools">
<ul class="nk-tb-actions gx-1">
<li>
<div class="drodown">
<a href="#" class="dropdown-toggle btn btn-icon btn-trigger" data-bs-toggle="dropdown"><em
class="icon ni ni-more-h"></em></a>
<div class="dropdown-menu dropdown-menu-end">
<ul class="link-list-opt no-bdr">
<li>
<a data-bs-toggle="modal" href="#mViewDetails"><em
class="icon ni ni-eye"></em><span>View
Details</span></a>
</li>
<li>
<a data-bs-toggle="modal" href="#mEditDetails"><em
class="icon ni ni-edit"></em><span>Edit
Details</span></a>
</li>
<li>
<a class="cursor" (click)="Toast.sendReminder()"><em
class="icon ni ni-send"></em><span>Send
Reminder</span></a>
</li>
<li>
<a data-bs-toggle="modal" href="#mChangeStatus"><em
class="icon ni ni-exchange"></em><span>Change Status</span></a>
</li>
<li>
<a href=""><em
class="icon ni ni-delete"></em><span>Delete
User</span></a>
</li>
</ul>
</div>
</div>
</li>
</ul>
</td>
</tr>
<!-- .nk-tb-item -->
</tbody>
</table>
Here is the TS Code
import { Component, OnInit } from '#angular/core';
import { Subject } from 'rxjs';
import { ToastService } from 'src/app/services/toast.service';
import { IDropdownSettings } from 'ng-multiselect-dropdown';
import { UserDetailService } from '../../services/user-detail.service';
import { Inter } from '../../inter';
import { HttpClient } from '#angular/common/http';
#Component({
selector: 'app-view-user',
templateUrl: './view-user.component.html',
styleUrls: ['./view-user.component.css']
})
export class ViewUserComponent implements OnInit {
constructor(public Toast: ToastService,
private userDetails: UserDetailService, private http: HttpClient) {
}
dtOptions: DataTables.Settings = {};
dtTrigger: Subject<any> = new Subject<any>();
dropdownList: any = [];
selectedItems = [];
allUsers: Inter[] = [];
dropdownSettings: IDropdownSettings = {
singleSelection: false,
idField: 'item_id',
textField: 'item_text',
selectAllText: 'Select All',
unSelectAllText: 'UnSelect All',
itemsShowLimit: 3,
allowSearchFilter: true
};
dataForTable: any;
fetch() {
this.http.get<any>('http://localhost:3000/user').subscribe(data => {
this.dataForTable = data;
console.log(this.dataForTable);
})
}
ngOnInit(): void {
this.dtOptions = {
pagingType: 'full_numbers',
language: {
searchPlaceholder: "Type Into Search"
}
};
this.fetch();
this.dropdownList = [
{ item_id: 1, item_text: 'Naan Shami' },
{ item_id: 2, item_text: 'Chicken Manchurian' },
{ item_id: 3, item_text: 'Pune' },
{ item_id: 4, item_text: 'Navsari' },
{ item_id: 5, item_text: 'New Delhi' }
];
this.get()
}
get() {
this.userDetails.get().subscribe((data) => {
this.allUsers = data;
});
}
delete(id: number) {
this.userDetails.delete(id).subscribe((data) => {
this.allUsers = this.allUsers.filter((_) => _.id !== id);
});
}
}
Here is the users.module.ts Code
import { NgModule } from '#angular/core';
import { CommonModule } from '#angular/common';
import { UsersRoutingModule } from './users-routing.module';
import { AddUserComponent } from './components/add-user/add-user.component';
import { NgbModule } from '#ng-bootstrap/ng-bootstrap';
import { FormsModule, ReactiveFormsModule } from '#angular/forms';
import { ViewUserComponent } from './components/view-user/view-user.component';
import { DataTablesModule } from 'angular-datatables';
import { NgMultiSelectDropDownModule } from 'ng-multiselect-dropdown';
import { HttpClientModule } from '#angular/common/http';
#NgModule({
declarations: [
AddUserComponent,
ViewUserComponent
],
imports: [
CommonModule,
UsersRoutingModule,
NgbModule,
FormsModule,
ReactiveFormsModule,
DataTablesModule,
HttpClientModule,
NgMultiSelectDropDownModule.forRoot(),
]
})
export class UsersModule { }
Please add the following.
this.dtTrigger.next();
It will update the rows in the table.
your component, declare the following
#ViewChild(DataTableDirective)
dtElement: DataTableDirective;
dtOptions: DataTables.Settings = {};
dtTrigger: Subject<any> = new Subject();
after you pull your data from the service
this.serviceName.getData().subscribe((data) => {
// ADD THIS
this.dtTrigger.next();
}, (err) => {
})
For more please refer to the answer.
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 {
}
When I have done a function to see the details of a formation already added, nothing is displayed.
Error
GET http://localhost:3001/formations/undefined 0 ()
EXCEPTION: Response with status: 0 for URL: null
Subscriber.js:246 Uncaught Response {_body: ProgressEvent, status: 0, ok: false, statusText: "", headers: Headers, …}
This is my show.html
<div class="panel panel-default" >
<div class="panel-heading">formation detail Form : You can see the detail information of an foration in this page of the EMS Apps.</div>
<div class="panel-body">
<form class="form-horizontal" *ngIf=forms>
<div class="form-group">
<label for="emp_name" class="col-sm-2 control-label">formation's Full title : </label>
<div class="col-sm-9">
<p class="form-control">{{forms.title}}</p>
</div>
</div>
<div class="form-group">
<label for="position" class="col-sm-2 control-label">formation url : </label>
<div class="col-sm-9">
<p class="form-control">{{forms.url}}</p>
</div>
</div>
<div class="form-group">
<label for="department" class="col-sm-2 control-label">formation description : </label>
<div class="col-sm-9">
<p class="form-control">{{forms.description}}</p>
</div>
</div>
</form>
</div>
</div>
this is my show.ts
import { Component, OnInit } from '#angular/core';
import { FormationService } from '../../services/formation.service';
import { Formation } from '../../../app/formation';
import { ActivatedRoute, Params, Router } from '#angular/router';
#Component({
selector: 'app-show',
templateUrl: './show.component.html',
styleUrls: ['./show.component.css']
})
export class ShowComponent implements OnInit {
constructor(
public formationService:FormationService,
public route:ActivatedRoute,
public router:Router
) { }
ngOnInit() {
this.getFormation();
}
formation:Formation;
getFormation(){
var id = this.route.snapshot.params['id'];
this.formationService.getFormation(id)
.subscribe(formation=>{
this.formation = formation;
})
}
}
this is my home.html
<table class="table table-bordered">
<thead>
<tr>
<td><b>Title</b></td>
<td><b>url</b></td>
<td><b>description</b></td>
<td width="275" align="center"><b>Action</b></td>
</tr>
</thead>
<tbody>
<tr *ngFor="let forms of formation | async " >
<td>{{forms.title}}</td>
<td>{{forms.url}}</td>
<td>{{forms.description}}</td>
<td width="275">
<a class="btn btn-info" routerLink="/show/{{forms._id}}">Detail</a>
<a class="btn btn-success" routerLink="/edit/{{forms._id}}" >Edit</a>
<a class="btn btn-danger" (click)="deleteFormation(forms._id)" >Delete</a>
</td>
</tr>
</tbody>
</table>
this is my service file
import { Injectable } from '#angular/core';
import { Http } from '#angular/http';
import 'rxjs/add/operator/map';
#Injectable()
export class FormationService {
constructor(private http:Http) { }
getFormations(){
return this.http.get("http://localhost:3001/formations")
.map(res => res.json());
}
addFormation(info){
return this.http.post("http://localhost:3001/formations",info)
.map(res => res.json());
}
getFormation(id){
return this.http.get("http://localhost:3001/formations/"+id)
.map(res => res.json());
}
deleteFormation(id){
return this.http.delete("http://localhost:3001/formations/"+id)
.map(res => res.json());
}
updateFormation(id, info){
return this.http.put("http://localhost:3001/formations/"+id,info)
.map(res => res.json());
}
}
I don't realy get you problem, but from what i see, you should
instead of
var id = this.route.snapshot.params['id'];
try to subscribe to the router using queryParams
this.formation = this.route.queryParams.pipe(map(params => {
this.id = params.id;
return this.formationService.getFormation(id)
})
in your html
<tbody *ngIf="formation | async as formation">
<tr *ngFor="let forms of formation">
</tr>
</tbody >
It seems that you send http request without id.
Just add a condition on the id:
getFormation(){
var id = this.route.snapshot.params['id'];
if(id){
this.formationService.getFormation(id)
.subscribe(formation=>{
this.formation = formation;
})
}
}
And it will be a good practice to add this check also in the service layer before sending request with 'id' as a a query param.
Good Day! I am a newbie in asp.net MVC 5 and is working on a form where one cell is editable then it will be saved in the database, along with the values of the other cells. I've managed to make the cell editable using contenteditable="true" . This is my View:
<div class="container">
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="col-lg-12">
<div class="col-lg-6"></div>
<div class="col-lg-6">
<div class="form-horizontal">
<div class="form-group">
#Html.LabelFor(m => m.CUSTOMER_ID, "Customer Name", new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("CUSTOMER_ID", ViewBag.CustomerName as IEnumerable<SelectListItem>, "--Select Customer--", new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.ORDER_DUE_DATE, "Due Date", htmlAttributes: new { #class = "col-lg-5" })
<div class="col-lg-7">
#Html.TextBoxFor(model => model.ORDER_DUE_DATE, "{0:yyyy-MM-dd}", new { #class = "form-control", #type = "date" })
#Html.ValidationMessageFor(model => model.ORDER_DUE_DATE, "", new { #class = "text-danger" })
</div>
</div>
</div><!--form-horizontal-->
</div>
</div><!--col lg 12-->
<table id="tbl_orderItems" class="table table-striped table-bordered table-hover dt-responsive nowrap" cellspacing="0">
<thead>
<tr>
<th>Item Code</th>
<th>Quantity</th>
<th>Unit</th>
<th>Item Description</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
#if (TempData["listOrder"] != null)
{
foreach (var items in TempData["listOrder"] as List<ebms.ViewModels.OrderItems>)
{ #Html.HiddenFor(modelItem => items.Id)
<tr>
<td>#items.PRODUCT_CODE</td>
<td contenteditable="true">#items.iQuantity</td>
<td>#items.MEASUREMENT_NAME</td>
<td>#items.ITEM_DESCRIPTION</td>
<td>#items.tmpStatus</td>
<td>
#Html.ActionLink("Remove", "Remove", new { id = items.Id },
new { onclick = "return confirm('Are sure want to remove?');" })
</td>
</tr>
}
}
</table>
<div id="menu1">
<ul>
<li>
<center><a>Select an Item</a></center>
<ul>
<li><a href='#Url.Action("Products", "Sales")'>Products </a></li>
</ul>
</li>
</ul>
</div>
<div class="form-group">
<div class="col-lg-3 pull-right">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</div>
}
</div>
I've put the contenteditable="true" in the quantity because it is the cell that should be editable. Most of the other values in there are from this form:
It will then be passed on to this form and the quantity should be editable.
Then the Customer will be chosen and the Order Due Date will be put in there as well. My problem is, the value that is typed to the editable cell is not saved in to the database. Can someone help me on how to use contenteditable="true" properly and then save it to the database? Thank you in advanced!
I'm newbie with Aurelia and frontend frameworks generally.
I have page with List
list.html
<template>
<require from="services/list-item"></require>
<div class="container-fluid">
<div class="row row-centered container-top-space">
<div repeat.for="item of items">
<list-item item.bind="item"></list-item>
</div>
</div>
</div>
</template>
list.js
import { inject } from 'aurelia-framework';
import { HttpClient, json } from 'aurelia-fetch-client';
#inject(HttpClient)
export class ListItem{
constructor(httpClient) {
this.items= [];
httpClient.configure(...);
}
}
and ListItem
list-item.html
<template>
<div class="row">
<div class="list-item">
<div class="form-control-inline" style="width:33%">
<span>${item.name} </span>
</div>
<div class="form-control-inline" style="width:54%">
<span>${item.value}</span>
</div>
<div class="pull-right" style="width:100px">
<button class="btn btn-list-item" type="submit" name="submit" click.delegate="edit($event.target.parentElement)">Edit</button>
</div>
</div>
</div>
</template>
list-item.js
import { bindable } from 'aurelia-framework';
export class ListItem{
#bindable item;
edit(element){
//I'd like to replace view component with update component here
}
}
I'd like to change template of list-item on list-item-edit when edit function will be called, but completely don't know how to make it.