Duplicate already rendered Vue.JS component - javascript

I have the following Vue.JS component definition:
<table>
<tr v-for="n in lines">
<td>in stock</td>
</tr>
<tr><td><button #click="lines++">+</button></td></tr>
</table>
Which looks like like this:
And it allows the user to edit each cell and press the "+" button to add more rows. I want to duplicate the whole component, all its content and functionality included so that I can move it to a different part of the page and still be able to use the duplicated component and the original. Like this:
The problem is that clicking on the "+" button of the duplicated table (the one on the left) will no longer work because it is a mere HTML clone.
How can I "deep-copy" the whole component so that it remains usable?
Note that the table can't be just wrapped into a v-for because the user is meant to clone more complex component structures like this.

Related

Map DOM element to memory object in Angular 6

I'm building a basic grid component with Angular 6. The grid itself is a <table>, with a <thead> for the header and a <tbody> section, where there are multiple rows. Each row has a fixed first column (which has de ID of the row), a dynamic number of 'positions' and a fixed last column (which holds an action combo button). Each of the positions contain a list of objects, dragged from an external tree component. All the rows, the positions and the list of objects inside them are generated from a DB, and displayed using *ngFor in the component template.
To make it clear, here's an schema of the grid:
The grid is built in this way:
<table #mainGrid>
<thead>
[...]
</thead>
<tbody (contextmenu)="showContextMenu($event)">
<tr *ngFor="let row of objectGrid; let i=index">
<td>{{ i }}</td>
<td *ngFor="let position of row.positions">
<ul class="object--list">
<li class="object--list--item" *ngFor="let object of position.objects">
{{ object.name}}
</li>
</ul>
</td>
<td><!-- CODE FOR THE ACTION BUTTON --></td>
</tr>
</tbody>
</table>
Each object has several actions associated to it (f.i. 'Delete', 'Locate in tree', 'Edit', etc) that must be chosen using the right button of the mouse. I'd like to avoid attaching an event handler to each object because sometimes the grid will contain more than 700 objects, so my idea is to attach only 1 contextmenu handler to the <tbody> (to disable right clicking on the table header) and use logic to find out the object where the user right clicked.
So far, I can use the event path property to identify the row, cell and the object (li element) where the right click occured. But now I'd like to know an elegant way of associating univocally the clicked li element to the position of the array that generated it.
For example, if I right click on the object 'Object 1.4.2', I'd like to get the reference to this.objectGrid[0].positions[3].objects[1].
Any suggestions? Thanks!
I couldn't find a safe way of doing it, so I've ended up adding the event handler to each of the objects that need it. So far, the performance for a grid with 500+ elements is pretty good, but I'm studying how to implement a virtualization to the grid component to load only the rows displayed on screen.

How can I pass in an <input> element to ng-for, which is bound to some ng-model?

Background
I am designing a reusable table component. The component was originally designed to merely display data in a table structure.
e.g you pass in a data array and a columnInfo array and the component renders an HTML table
There has been a change in requirements however, and now the table needs to support input fields.
Textfield 1 Textfield 2 Textfield 3 Input 1 Input 2
testestestestestsetestsetestestsetestestsetsetsett *dropdownhere* *textbox here*
The Problem
First and fore-most , simply displaying an "extra textbox column" on every row has proven difficult.
I've used a simple ng-content with single-selector
Table Component. html
<tr *ngFor="let row of rows" (click)="onCellClick(row)">
<td *ngFor="let column of _columns">
{{ getData(row,column) }}
</td>
<td><ng-content select="[test]"></ng-content></td>
</tr>
Parent Component
<table-component [columns] = "tableHeaders"
[data]="_allTasksArray"
(cellEvent)="getActionUrl($event)"
[filterAllColumns]="true"
>
<div test >
<h1>TEST</h1>
</div>
</table-component>
However this does not work as expected, the h1 TEST is only rendered in ONE row. And after some digging around, I discovered that the template passed in from ng-content can only ever be displayed once.
Not very useful for my requirements.
The Question
So if there exists a way to pass in an HTML element to a component for use with ngFor, how then can I associate these inputs with a value?
for example If I wanted to pass in a drop down pre-populated with values specific to each row in the table.
This is how it should work
<table-component>
<template-for-content>
<input [(ngModel)]="This would be linked row[column.name] in the table">
</template-for-content>
</table-component>
Table
<td><ng-content someWayOfPassingDataBackToTemplate></ng-content></td>
You should take a look at the reactive forms module for angular 2, I think this would be a good use case for it. There is a good walkthrough of it in the Angular 2 docs. Reactive forms let you define forms 'programmatically' using objects. The walkthrough shows you have to set it up so you can pass in an array of configuration objects (each object representing a single input) into a reactive-form directive and it will iterate over the array and render an input based off each configuration object. It also shows how to get the data out of a reactive form.

Force ngRepeated element to redraw after filtering

I need to redraw rows after filtering ngRepeat-ed array with "search" like filter, in order to highlight the "needle".
I wrote a filter function for the parsed text, but it does not fire once the filtering (the search like one) is done.
<tr ng-repeat="transaction in collection | orderBy:sortExp:sortReverse | filter:multiFilter()">
<td ng-repeat="(prop,value) in transaction" title="{{prop}}">
{{value | filter:highlightNeedle(prop)}}
</td>
</tr>
I'm assuming Angular is not redrawing these rows in order to save performance, but that is preventing me from implementing this feature.
Can you add you javascript ? The controller and the highlightNeedle thing ?
Just considering the name of you filter, i think you're not using it for what's it's been made for.
If you want to hightlight your cell you should put use something like ng-class or ng-style. see https://docs.angularjs.org/api/ng/directive/ngClass
A example would be to have a css class "myClass" doing the highlighting stuff and add to your
ng-class="{myClass:check(prop)}"
where "check" is a function declared in the scope returning true/false.
Note that if your table is really big, you may have some trouble because angular will watch for change and create scope for every {{}}.

style lost after item returned to display

In an html form, I have a table that I hide or display based on a radio button choice. When the table is hidden and then brought back, one of the style settings is lost. I would like to keep the same layout when the table is displayed.
HTML for the table
<table id="tblAutomated">
<tr>
<td>Are the deposits automated?</td>
<td id="tdAutomated" style="text-align:right"><input type="radio" name="rbAutomated" value="yes">Yes <input type="radio" name="rbAutomated" value="No">No</td>
</tr>
</table>
JS for the radio button just the relevant part
document.getElementById('tblAutomated').style.display='block';
document.getElementById('tdAutomated').style.textAlign='right';
But IE Dev Tools shows an unhandled exception for that second JS line. "Object doesn't support property or method."
So, I tried adding a class to the <td>.
<td id="tdAutomated" class="tblRight">
and I added the text-align style to that class. Then I changed the JS to try two other methods: .hasClass and .addClass. But both of those methods failed, too.
Is there a method that will either set that alignment correctly or allow the class to be added?
EDIT
Here are the images of what I see and what Dev Tools shows is happening in the HTML. Using both methods, I see no reason why the cell shouldn't go back to where it was originally.
I was able to resolve this by putting the table inside a <div> and changing the display for that, instead.

myGrid.setStore in nested div

I am trying to develop a ersi map javascript page.
I am creating
var myData = { items: myItems };
var myStore = new dojo.data.ItemFileReadStore({ data: myData });
These create correctly and have the correct data in
I have a problem updating a dojox.grid.DataGrid with the myGrid.setStore(myStore);
The code I have for the grid is:
<table dojotype="dojox.grid.DataGrid" jsid="myGrid" noDataMessage="No results found in the current map extent" style="width:100%;height:100%;" selectionMode="none">
<thead>
<tr>
<th field="NAME" width=75%>Neighborhood</th>
<th field="ownPct" width=25%>% Own</th>
</tr>
</thead>
</table>
This table in nested in a number of divs in the HTML.
I suspect that when I run myGrid.setStore(myStore); it cannot find the table in the DOM.
If I move the table to be out of any DIV's and have it directly after the <body> tag (see link). the code will work and populate the table. If I move the table to the end of the HTML just before the </body> tag it will work (see link). But when I put the table in the nested Divs then it will not populate (see link). this should be on the policy tab!!
I hope i make sense, this has been driving me crazy
thanks in advance Paul
I think the problem is not with setStore, but one or two other things.
When the DataGrid is instantiated, it attempts to detect the space available (to determine how many rows to render etc). You've told it to be 100% of its parent div, but remember that divs have height 0px by default!
So, you can try to give the grid (or gridDiv) an explicit height. However, the grid is also in an inactive tab so it still detects it has no height (it's invisible, after all!).
So, next you can try to set the grid's tab as the active one (i.e. <div class="tab-pane active" id="policies">). That should give you a rendered grid when the page loads.
Alas, you don't want the grid's tab to be the active one. So the final solution is that you need to explicitly tell the grid to recalculate its height (myGrid.resize()) when the policy tab is being activated. I haven't used bootstrap's tabs, so I don't know exactly how to do that - perhaps you do?

Categories

Resources