- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
此处使用 Angular 6
我想要一些关于设计我的 UI 组件的意见。所以基本上我们已经在 AngularJs 中设计了当前的功能,但是在这个使用 Angular 6 的新应用程序我想知道是否有更好的方法。
下面是我想要设计的 UI 流程。
用户在顶部填写表单,基本上是一些文本框和下拉菜单。
经过上述选择后,我显示了一个 HTML 表格,其中包含 3 个静态列和几个按钮,如下所示:
ID 类型环境+添加列 -删除行+添加行
上面的 Id、Type 和 Env 是始终存在的 3 个静态列。现在,如果用户想要添加更多列(动态),他可以单击“添加列”按钮,用户可以在其中输入自己的特定列名称。还应该有删除动态列的功能。用户添加完列后,可以单击“添加行”,这将创建一个动态行,然后用户可以将数据输入到表中。用户添加行后,用户可以单击“删除行”按钮来删除该行。
用户完成向表中添加列和行后,末尾有一个提交按钮,它将以 Json 格式将上述内容发送到我的 API,这将然后保存整个表单。
仅供引用,我已经在 angularjs 中有一个工作版本,其中我对每一行使用 contenteditable ,如下所示:
<tr ng-repeat="r in targetTable.rows">
<td class="unique-id">{{r.id}}</td>
<td contenteditable="true" ng-repeat="column in targetTable.columns" ng-model="r[column.id]" ng-blur="!r.id? addNewRow(r[column.id], r): undefined"></td>
<td class="blank" colspan="2"></td>
</tr>
在此处查看演示:
https://codepen.io/anon/pen/QXwjwM
我需要输入的是如何设计这个 html 表,并具有在 Angular 6 中添加/删除动态行和列的所有功能。是否有一些开源可用,或者是否有人可以帮助我提供一些示例。或者如果我需要手动创建所有这些。与我在 AngularJs 中所做的类似。
谢谢
有人有意见吗?
最佳答案
结合我的两条评论,我创建了这个 stackblitz
我使用了 Material 表,因为我懒得格式化表格。正如所评论的,我们唯一需要使用 mat-table 的是将表单数组的控件作为数据源
dataSource = this.myformArray.controls;
表格的列变成这样
<ng-container matColumnDef="surname">
<th mat-header-cell *matHeaderCellDef> Surname </th>
<td mat-cell *matCellDef="let element">
<input arrow-div [formControl]="element.get('surname')">
</td>
</ng-container>
是的,使用 [formControl]=element.get('nameOfField') 很简单
有趣的工作是使箭头键可以在“单元格”之间移动。我使用指令。但由于我讨厌使用 @Output()
创建指令,所以我使用了辅助服务。
如果我们不使用服务,我们的 .html 看起来像
<input arrow-div [formControl]="element.get('id')" (arrowEvent)="move($event)">
<input arrow-div [formControl]="element.get('name')" (arrowEvent)="move($event)">
<input arrow-div [formControl]="element.get('surname')" (arrowEvent)="move($event)">
...
如果我们使用服务,我们的 html 就会变得更加透明
<input arrow-div [formControl]="element.get('id')" >
<input arrow-div [formControl]="element.get('name')" >
<input arrow-div [formControl]="element.get('surname')" >
...
并在应用程序中我们订阅该服务。
服务很简单
export class KeyBoardService {
keyBoard:Subject<any>=new Subject<any>();
sendMessage(message:any)
{
this.keyBoard.next(message)
}
}
只是一个主题和一个将值发送到主题的方法。
该指令仅在按下箭头键时监听并向按键发送者发送消息。好吧,我发送一个类型为 {element:...,action:..} 的对象来发送更多信息。
export class ArrowDivDirective {
constructor( private keyboardService:KeyBoardService,public element:ElementRef){}
//@Output() arrowEvent:EventEmitter<any>=new EventEmitter();
@HostListener('keydown', ['$event']) onKeyUp(e) {
switch (e.keyCode)
{
case 38:
this.keyboardService.sendMessage({element:this.element,action:'UP'})
break;
case 37:
if (this.element.nativeElement.selectionStart<=0)
{
this.keyboardService.sendMessage({element:this.element,action:'LEFT'})
e.preventDefault();
}
break;
case 40:
this.keyboardService.sendMessage({element:this.element,action:'DOWN'})
break;
case 39:
if (this.element.nativeElement.selectionStart>=this.element.nativeElement.value.length)
{
this.keyboardService.sendMessage({element:this.element,action:'RIGTH'})
e.preventDefault();
}
break;
}
}
}
好吧,当我们单击 lfet 和右箭头时,我会考虑当您第一次或在输入初始时发送或不发送 key 。
app.component 只需订阅服务并使用 ViewChildren 来存储所有输入。小心点! mat-table 中 viewchildren 的顺序是从上到下、从左到右
@ViewChildren(ArrowDivDirective) inputs:QueryList<ArrowDivDirective>
constructor(private keyboardService:KeyBoardService){}
ngOnInit()
{
this.keyboardService.keyBoard.subscribe(res=>{
this.move(res)
})
}
move(object)
{
const inputToArray=this.inputs.toArray()
const rows=this.dataSource.length
const cols=this.displayedColumns.length
let index=inputToArray.findIndex(x=>x.element===object.element)
switch (object.action)
{
case "UP":
index--;
break;
case "DOWN":
index++;
break;
case "LEFT":
if (index-rows>=0)
index-=rows;
else
{
let rowActual=index%rows;
if (rowActual>0)
index=(rowActual-1)+(cols-1)*rows;
}
break;
case "RIGTH":
console.log(index+rows,inputToArray.length)
if (index+rows<inputToArray.length)
index+=rows;
else
{
let rowActual=index%rows;
if (rowActual<rows-1)
index=(rowActual+1);
}
break;
}
if (index>=0 && index<this.inputs.length)
{
inputToArray[index].element.nativeElement.focus();
}
}
*更新如果我们想添加动态列,请添加新的两个变量(加上“displayedColumns”
displayedColumns: string[] = ['name','surname','delete'];
displayedHead:string[]=['Name','Surname']
displayedFields:string[] = ['name','surname'];
我们的 table 变得像
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<!-- All columns -->
<ng-container *ngFor="let col of displayedFields;let i=index" [matColumnDef]="col">
<th mat-header-cell *matHeaderCellDef> {{displayedHead[i]}} </th>
<td mat-cell *matCellDef="let element">
<input arrow-div [formControl]="element.get(col)">
</td>
</ng-container>
<!---column delete-->
<ng-container matColumnDef="delete">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let element;let i=index;">
<button arrow-div mat-button (click)="delete(i)">delete</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
添加列的新函数必须向数组的每个 FormGroup 添加一个 FormControl,实现变量 displayedColumns、displayedHead 和 displayedFields
addColumn()
{
let newField="Column"+(this.displayedFields.length+1)
this.myformArray.controls.forEach((group:FormGroup)=>{
group.addControl(newField,new FormControl())
})
this.displayedHead.push(newField)
this.dataSource = [...this.myformArray.controls];
this.displayedFields.push(newField);
this.displayedColumns=[...this.displayedFields,"delete"];
}
在此another stackblitz我添加了此功能(以及如何删除行以及如何创建新行)
更新 2 回答如何不“硬编码” formArray 实际上它都在里面。如果我们想象我们有一个像这样的数组
ELEMENT_DATA: any[] = [ { name: '1', surname: 'one' }, { name: '2', surname: 'two' }, { name: '3', surname: 'three' }, ]; )
我们需要使用数组为 displayedHead、displayedFields 和 displayedColumns 赋值:
displayedHead:string[]=Object.keys(this.ELEMENT_DATA[0]).map(x=>x.substring(0,1).toUpperCase()+x.substring(1))
displayedFields:string[] = Object.keys(this.ELEMENT_DATA[0]);
displayedColumns:string[]=[...this.displayedFields,'delete']
为了初始化 FormArray,我们将改进函数“add”,以允许传递一个对象作为参数来为表单赋值
add(data:any=null)
{
const newGroup=new FormGroup({});
this.displayedFields.forEach(x=>{
//see that if data!=null we create the FormControl with the value
//of data[x]
newGroup.addControl(x,new FormControl(data?data[x]:null))
})
this.myformArray.push(newGroup)
this.dataSource = [...this.myformArray.controls];
}
至少创建一个函数initArray
initArray(elements:any[]){
elements.forEach(x=>{
this.add(x);
})
}
并在ngOnInit中调用它
this.init(this.ELEMENT_DATA)
好吧,如果我们没有变量中的数组 - 通常我们从服务中获取值 - 我们需要将所有这些放入服务的订阅函数中
this.myserviceData.getData().subscribe(res=>{
displayedHead:string[]=Object.keys(res[0]).map(x=>x.substring(0,1).toUpperCase()+x.substring(1))
displayedFields:string[] = Object.keys(res);
displayedColumns:string[]=[...this.displayedFields,'delete']
this.initArray(res)
})
更新允许用户更改列名称
在表中,每列的“头”可以是任何内容。所以我们可以定义一个变量
columnSelect = -1;
我们正在创建一个更复杂的 header
<th mat-header-cell *matHeaderCellDef>
<span [style.display]="columnSelect!=i?'inline':'none'" (click)="selectColumn(i,columnName)">{{displayedHead[i]}} </span>
<input #columnName [style.display]="columnSelect==i?'inline':'none'" [ngModel]="displayedHead[i]" (blur)="changeColumnName(i,columnName.value)"/>
</th>
查看标题或是输入或跨度(如果“selectColumn”等于列。请记住,列是从 0 开始编号的 - 这就是原因,因为如果 selectColumn=-1,则没有已选择列。
我们使用模板引用变量“#columnName”将值传递给函数(模糊)以及何时(单击)跨度。这允许我们创建两个函数
selectColumn(index: number, inputField: any) {
this.columnSelect = index; //give value to columnSelect
setTimeout(() => { //in a setTimeout we make a "focus" to the input
inputField.focus();
});
}
有必要在 setTimeout 内设置焦点,以允许 Angular 重新绘制标题,然后设置焦点。这也是我们使用 [style.display] 而不是 *ngIf 的原因。 (如果我们使用 *ngIf,则“inputField”值为 null)
更改名称的函数有点复杂
changeColumnName(index, columnTitle) {
const oldName = this.displayedFields[index];
const columnName = columnTitle.replace(/ /g, "").toLowerCase();
if (columnName != oldName) {
this.myformArray.controls.forEach((group:FormGroup)=>{
group.addControl(columnName,new FormControl(group.value[oldName]))
group.removeControl(oldName)
})
this.displayedHead.splice(index, 1, columnTitle);
this.displayedColumns.splice(index, 1, columnName);
this.displayedFields.splice(index, 1, columnName);
}
this.columnSelect = -1;
}
基本上,我们将一个新的 formControl 添加到数组中并删除旧的。我选择“字段”的名称是删除所有空格后小写的标题。
关于javascript - Angular 6 : HTML table create dynamic columns and rows,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56562871/
大家好, 我看到了来自 java 项目中的 jsp 页面。 想问一下这些html标签有什么区别。 请多多指教。 示例代码如下: 最佳答案 使用struts-html标签库,其中只是普
我有一个页面,我正在从电子邮件中读取 HTML。 有时,来自电子邮件的文本包含 HTML 和 CSS,它完全改变了我的页面样式。 我不希望我的页面样式因此受到影响。我如何严格阅读特定 div(框)内的
我知道有类似的问题,但我想对我的特定代码进行一些输入。 我有一个图像,我将其切成 9 块,并创建了一个 3x3 HTML 表来显示它。 但是我的表在行之间有空格,但在列之间没有空格。我没有使用任何 C
编辑:Waylan 的回答成功了!谢谢! 我正在尝试压缩文档的 .html 文件以发送给客户。目标是获得与浏览实际网站相同的体验。 打开 .html 文件时,单击的任何链接都会转到父文件夹,而不是特定
编辑:Waylan 的回答成功了!谢谢! 我正在尝试压缩文档的 .html 文件以发送给客户。目标是获得与浏览实际网站相同的体验。 打开 .html 文件时,单击的任何链接都会转到父文件夹,而不是特定
这是 question 的扩展.我正在尝试解析嵌入在 Blogger 博客的 XML 备份中的 HTML 片段,并用 InDesign 标签重新标记它们。 Blogger 并未对其任何帖子的 HTML
我知道在 html 中元素之间的换行符被视为空格,但我认为当您尝试使用响应式布局时这非常可怕。 例如,这里我们有预期和正确的行为,但要获得它,我必须删除元素之间的 html 中的换行符: https:
我正在尝试将文本文件显示为 html。我正在使用 ionic 。我正在发送一个 html 格式的响应,但在一个文本文件中发送到配置文件页面。它在 .ts 页面的变量名中。 @Component({
假设我有一个 html 文档: test 我想在浏览器中显示该代码。然后我会创建类似的东西: <html>test<html> 为了在中间制作 gubbins,我有一个函数
HTML 元素和 HTML 标签有什么区别?渲染有什么区别吗?使用标签或元素时有什么特殊注意事项吗? 最佳答案 是一个标签,特别是一个开始标签 也是一个标签,一个结束标签 This is a para
我有这个表格的模态形式。该表正在填充大量数据,但我不想分页。相反,我想以模式形式降低表格的高度并为表格添加溢出。下面是我的代码,但它不起作用。 请问我该如何实现? CSS #table{
我记得有一个 Linux 命令可以从给定的 URL 返回 HTML 代码。您可以将 URL 作为此命令的参数,然后返回 HTML 代码,而不是在浏览器中输入 URL。 哪个命令执行此操作? 最佳答案
我有一个 html 页面,我想在其中包含另一个有很多链接的 html 页面。我能够使用 iframe 实现它,但我希望 iframe 内的页面具有与原始页面相同的文本和链接颜色属性,我不想要滚动条,我
我正在使用 HTML 写一本书。如果我把它写在一个 html 文件中,整个代码就会变长,所以我想将每一章保存到不同的文件中,然后将它们加载到主 html 中。我的意思是有像 chapter1.html
在显示之前,我必须将一个网站重定向到另一个网站。我试过使用 .htaccess,但它给我带来了问题。我也使用过 javavscript 和 meta,但在加载我要从中传输的页面之前它不起作用。帮助?
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
如何打印“html”标签,包括“”?如何在不使用文本区域和 Javascript 的情况下对任何标签执行此操作? 最佳答案 使用HTML character references : <html
我需要将 Ruby on Rails 应用程序中的 html.slim 文件转换为 html.erb。有什么简单的方法吗?我尝试了 Stack Overflow 和其他网站中列出的许多选项。但对我没有
这个问题在这里已经有了答案: Is it necessary to write HEAD, BODY and HTML tags? (6 个答案) 关闭 8 年前。 我在 gitHub 上找到了这个
如果不允许通过 JavaScript 进行额外的 DOM 操作,我正在寻找可以加载外部资源的元素列表。我正在尝试使用 HTML 查看器托管来自第三方的电子邮件,当发生这种情况时,我需要删除任何自动加载
我是一名优秀的程序员,十分优秀!