*ngFor with local assignment with the async pipe and reducing number of subscriptions - javascript

I have code similar to the following in the template file of a custom Angular component I have written:
<item
[class.disabled]="domain?.disabled | async"
[class.hidden]="!(domain?.subscribed | async) && !showHiddenDomains || (domain?.deleted | async)"
[disabled]="domain?.disabled | async"
[hideHealth]="true"
*ngFor="let domain of (forest?.domains | async)"
[status]="domain?.status | async"
(expand)="collapseDomain($event, domain)">
<span header>
<div [class.container-disabled]="!(domain?.disabled | async) && !(domain?.iconType | async)">
<spinner-2 [promise]="spinnerPromise" *ngIf="domain?.disabled | async"></spinner-2>
<font-icon class="domain-header-icon-{{domain?.statusString | async}}" [type]="domain?.iconType | async" *ngIf="!(domain?.disabled | async)"></font-icon>
</div>
<div>{{domain.name}}</div>
</span>
.
.
.
I've been reading this article and am wondering if I can take advantage of the *ngIf with local assignment discussed at the bottom of the page. I read this:
Here we are creating a local template variable that Angular assigns
the value from the Observable. This allows us to interact directly
with our user Object without having to use the async pipe over and
over.
On this page and was wondering if I could take advantage of this so that I do not have to keep reusing the async pipe over and over again as I feel it is drastically reducing performance on my page.
Thoughts? Thanks
UPDATE
I've been able to reduce most of the code to this fashion by wrapping ng-containers around blocks of code, for example:
<ng-container *ngIf="forest?.domains | async as domains">
<div *ngFor="let domain of domains">
.
.
.
</div>
</ng-container>
Some of these domains have properties attached to them that are in the form of:
property: Observable.from([true]);
Anyone know what the above does?

Assuming that each of the domain object in the domains are subscribable entries.
Just create a component called ItemHeader as below and dumb down the subscriptions into one.
Change your html as below
<item
[class.disabled]="domain?.disabled | async"
[class.hidden]="!(domain?.subscribed | async) && !showHiddenDomains || (domain?.deleted | async)"
[disabled]="domain?.disabled | async"
[hideHealth]="true"
*ngFor="let domain of (forest?.domains | async)"
[status]="domain?.status | async"
(expand)="collapseDomain($event, domain)">
<item-header [domain]="domain | async"></item-header>
.
.
.
//item-header.component.ts
#Component({
selector: 'item-header',
templateUrl: './item-header.component.html'
})
export class ItemHeaderComponent implements OnInit {
#Input() domain: Domain
constructor(){}
}
//item-header.component.html
<span header>
<div [class.container-disabled]="!(domain?.disabled | async) && !(domain?.iconType | async)">
<spinner-2 [promise]="spinnerPromise" *ngIf="domain?.disabled | async"></spinner-2>
<font-icon class="domain-header-icon-{{domain?.statusString | async}}" [type]="domain?.iconType | async" *ngIf="!(domain?.disabled)"></font-icon>
</div>
<div>{{domain.name}}</div>
</span>

Related

Merge specific columns in UI Grid

I have a ui grid where i require to merge some of the middle columns. It should look something like below :
Name | Address | Comment | Job | College | Married
----------------------------------------------------------
Keshvi | India | New | Not applicable | No
----------------------------------------------------------
I am currently using rowTemplate.
function rowTemplate() {
return ' <div ng-repeat="(colRenderIndex, col) in grid.appScope.customiseRowsDeletedBy(colContainer.renderedColumns) track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ui-grid-cell></div>' +
' <div class="other-override-background" >{{row.entity.job}}</div>' +
' <div ng-repeat="(colRenderIndex, col) in [colContainer.renderedColumns[5]]) track by col.colDef.name" class="ui-grid-cell" ng-class="{ \'ui-grid-row-header-cell\': col.isRowHeader }" ng-style="{position:\'absolute\, display:\'block\'}" ui-grid-cell ></div>'
'</div>';
}
$scope.customiseRowsDeletedBy = (arr) => arr.slice(0, 2);
however, my output looks something this :
Name | Address | Comment | Job | College | Married
----------------------------------------------------------
Keshvi | India | New | Not applicable |
----------------------------------------------------------
No
----------------------------------------------------------
The third div shifts the content down.
Any idea how to go about?
TableData objects have a property called 'ColSpan' that you can use.
document.getElementById("myTd").colSpan = "2";
I'm not too familiar with rowTemplate but perhaps it has a similar property.

Display option selected with codeigniter

I want to ask for my code option selected with 2 tabel in page register
table prodi
+-------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+---------+-------+
| id_prodi | varchar(3) | NO | PRI | NULL | |
| nama_prodi | varchar(30) | NO | | NULL | |
| id_fakultas | varchar(3) | NO | MUL | NULL | |
| id | int(2) | NO | MUL | NULL | |
+-------------+-------------+------+-----+---------+-------+
and
table jurusan
+---------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+-------------+------+-----+---------+-------+
| id_fakultas | varchar(3) | NO | PRI | NULL | |
| nama_fakultas | varchar(40) | NO | | NULL | |
+---------------+-------------+------+-----+---------+-------+
here's view :
<label for="fakultas">Fakultas : </label>
<select id="fakultas" name="fakultas_user" onChange="fakultas">
<?php
foreach ($qfakultas as $fakultas) {
echo "<option value=".$fakultas->kd_fakultas.">".$fakultas->nama_fakultas."</option>";
}
?>
</select>
<hr>
<label for="jurusan">Jurusan : </label>
<select id="jurusan" name="jurusan_user" onChange="jurusan">
<?php
foreach ($qprodi as $prodi) {
echo "<option value=".$prodi->kd_prodi.">".$prodi->nama_prodi."</option>";
}
?>
</select>
but I will display 'nama_prodi' based on 'id_fakultas"
register with option value
How to display when I click 'nama_fakultas' then display 'nama_prodi' based on 'id_fakultas' ?
Thanks
Here is the Ajax code that I can help, only to get nama_prodi based on id_falkutas.
You can use this code for your project, there is something you need to do. Not just copy the code. Just a few step (ID Lang : Jangan dicopy mentah2, hanya beberapa langkah saja untuk edit).
Change YOUR_URL_HERE into your base_url() or create var for it.
Change nama_controller into your controller name in CI_Controller
Change nama_fungsi into your function to get the data from your model (database). Example : ambil_data_jurusan.
Remove your foreach - echo <option> and onchange from your view.
Add the script into your view files or create a new .js file.
Please help me to mark as correct answer if this code helped you. ( tolong dibantu gan )
See Code Example :
<script>
$("#falkutas").on('change', function() {
$.ajax({
type:"POST",
url:'YOUR_URL_HERE/nama_controller/nama_fungsi',
data:{"falkutas_user":falkutas_user,"csrf_token":$("input[name=csrf_token]").val()},
dataType:'json',
success: function(result) {
for(var i=0; i<result.length; i++) {
res += '<option value="'+result[i]['id_prodi']+'">'+result[i]['nama_prodi']+'</option>';
}
$(document).ready(function() {
$("#prodi").html(res);
});
},
error: function(result) {
$(document).ready(function() {
$("#prodi").html(''); //empty select value
});
}
});
}
</script>
Then, in your function code :
// Inside function ambil_data_jurusan(), harusnya sudah jalan kalau gini
$return = $this->model->get_jurusan($this->input->post('falkutas',TRUE));
if(count($return)>0) {
echo json_encode($return);
}
In your view, just let select empty like this.
<select id="jurusan" name="jurusan_user">
</select>

Angular 4 and ngx-translate: avoid duplicate of translate pipe in template for the same key

I have the following code in a template from an Angular 4 app using ngx-translate
<a [routerLink]="['birthdays']" [title]="'birthdays.title' | translate">
{{ 'birthdays.title' | translate }}
</a>
this works perfect. But I have to duplicate the code that retrieves the translate for 'birthdays.title'. Is there a way to, in the template, set it to a variable and use this variable?
Something like (pseudo code):
<a [routerLink]="['birthdays']" [title]="'birthdays.title' | translate as title">
{{ title }}
</a>
I don't think this is needed but you could make a get variable in your .ts and then use that variable in your html:
// This is needed because translate get is async :(
birthdayString: string = '';
ngAfterViewInit() {
this.translate.get('birthdays.title')
.subscribe(value => { this.birthdayString = value; })
}
get birthdayText() {
return birthdayString;
}
And in your html file:
<a [routerLink]="['birthdays']" [title]="birthdayText">
{{ birthdayText }}
</a>

How to add translation filter to notification of ngAdmin?

My code is like this:
function enableUser(Restangular, $state, notification) {
...
...
notification.log(
{{ "DISABLED_LOG_DISABLE" | translate }},
{ addnCls: 'humane-flatty-success' });
}
I found that it will display {{ "DISABLED_LOG_DISABLE" | translate }} directly to the screen but what I need is Disabled employee when I give it {'DISABLED_LOG_DISABLE': 'Disabled employee'}
This expression is used in HTML file "{{ "DISABLED_LOG_DISABLE" | translate }"
What you should do is inject $translate and then you call it. For example:
$translate('DISABLED_LOG_DISABLE').then(function(translatedString) {...})
I guess you are using angular-translate.

table setAttribute not working properly in IE

I am trying to build an application that generates a custom list item which will be displayed on the screen dynamicly(like contact list update), and have the following code which works pretty well on both IE and Firefox.
<html>
<head>
<style type="text/css">
.divCss table{
width:100%;
height:130px;
}
.divCss {
width:100%;
height:100%;
border:solid 1px #c0c0c0;
background-color:#999000;
font-size:11px;
font-family:verdana;
color:#000;
}
.divCss table:hover{
background-color :#FF9900;
}
</style>
<script type="text/javascript" language="javascript">
var elementCounts = 0;
function myItemClicked(item)
{
alert("item clicked:"+item.id);
}
function createItem()
{
var pTag = document.createElement("p");
var tableTag = document.createElement("table");
tableTag.id = "" + (elementCounts++);
tableTag.setAttribute("border","1");
tableTag.setAttribute("cellpadding","5");
tableTag.setAttribute("width","100%");
tableTag.setAttribute("height","130px");
tableTag.onclick = function() {myItemClicked(this);};
var tBody = document.createElement("tbody");
var tr1Tag = document.createElement("tr");
var tdImageTag = document.createElement("td");
tdImageTag .setAttribute("width","100px");
tdImageTag .setAttribute("rowspan","2");
var imgTag = document.createElement("img");
imgTag.setAttribute("width","100px");
imgTag.setAttribute("height","100px");
imgTag.id = "avatar";
tdImageTag .appendChild(imgTag);
var tdTextTag= document.createElement("td");
tdTextTag.setAttribute("height","30%");
tdTextTag.setAttribute("nowrap","1");
tdTextTag.setAttribute("style","font-weight: bold; font-size: 20px;");
tdTextTag.id = "text";
tdTextTag.innerHTML = "text";
tr1Tag.appendChild(tdImageTag);
tr1Tag.appendChild(tdTextTag);
var tr2Tag = document.createElement("tr");
var tdAnotherTextTag = document.createElement("td");
tdAnotherTextTag.setAttribute("valign","top");
tdAnotherTextTag.id = "anotherText";
tdAnotherTextTag.innerHTML = "Another Text";
tr2Tag.appendChild(tdAnotherTextTag );
tBody.appendChild(tr1Tag);
tBody.appendChild(tr2Tag);
tableTag.appendChild(tBody);
tableTag.className ="divCss";
pTag.appendChild(tableTag);
document.getElementById("list").appendChild(pTag);
}
function clearList()
{
document.getElementById("list").innerHTML = "";
elementCounts = 0;
}
</script>
</head>
<body>
<input id="btn1" type="button" value="create item" onclick="createItem();" />
<input id="btn2" type="button" value="clear list" onclick="clearList();" />
<div id="list" class="divCss" style="overflow: scroll;"></div>
</body>
</html>
This code generates a new table element on click of "create item" button and adds it inside a div element on the main page.
The table element is supposed to be like the following
+---------------+--------------------+
| | Text |
| Image with | |
| rowspan of +--------------------|
| 2 | Another Text |
| | |
+---------------+--------------------+
The above code does showup properly on firefox, however on IE, the rowspan is kinda ignored and the output looks like
+---------------+--------------------+
| Image with | Text |
|rowspan ignored| |
|---------------+--------------------|
| Another Text | |
| | |
+---------------+--------------------+
Can anyone help me why this must be happening? I also checked writing direct tags ( instead of using createElement and appendChild), and that works, but the dynamic generation seems to be problamatic. Am I doing anything worng here?
Also, after adding the generated table elements in the div element ( "list" ), there seems to be some gap between consecutive table elements and am not able to remove it even if i specify margin and padding as 0 in div tag.
Any help would be much appreciated.
Thanks.
EDIT: About the gap between table elements inside div.
Here is the output as expected: ( This works in jsfiddle as suggessted by Shadow Wizard ).
+------------------------------------+
| List Element 1 |
+---------------+--------------------+
| | Text |
| Image with | |
| rowspan of +--------------------|
| 2 | Another Text |
| | |
+---------------+--------------------+
| List Element 2 |
+---------------+--------------------+
| | Text |
| Image with | |
| rowspan of +--------------------|
| 2 | Another Text |
| | |
+---------------+--------------------+
| List Element 3 |
+---------------+--------------------+
| | Text |
| Image with | |
| rowspan of +--------------------|
| 2 | Another Text |
| | |
+---------------+--------------------+
Here is the output that i get on chrome, ie, firefox..
+------------------------------------+
| List Element 1 |
+---------------+--------------------+
| | Text |
| Image with | |
| rowspan of +--------------------|
| 2 | Another Text |
| | |
+---------------+--------------------+
Gap
+------------------------------------+
| List Element 2 |
+---------------+--------------------+
| | Text |
| Image with | |
| rowspan of +--------------------|
| 2 | Another Text |
| | |
+---------------+--------------------+
Gap
+------------------------------------+
| List Element 3 |
+---------------+--------------------+
| | Text |
| Image with | |
| rowspan of +--------------------|
| 2 | Another Text |
| | |
+---------------+--------------------+
Sorry for explaining things like this. I was not able to upload my snapshots. However, you can see the difference between jsfiddle and other browser effects by opening the page as html file in any browser.
EDIT (Shadow_Wizard) - here is the screenshot:
In IE, the attributes are pretty limited and better be set "directly" and not via setAttribute.
Try this instead:
tdImageTag.rowSpan = 2;
Same for width and height: those better be set as part of the style:
imgTag.style.width = "100px";
imgTag.style.height = "100px";
Edit: by gaps do you mean the parts marked with red circles?
Edit II: if you see difference between jsFiddle and your own file it might mean you're missing DOCTYPE declaration. Try adding this line on top of your code, above the <html> tag:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
jsFiddle is adding such line by itself, you can View Source to see it.
Also, I saw you're running the file locally... that's also not good you better run it as part of website to simulate "real" web page.
Try tdImageTag.setAttribute("rowSpan","2"); - it needs to be the upper case S
The gaps between the table elements may happen because the default cellspacing try this code: tableTag.cellSpacing=0;
Also if you are using the strict mode you can set the cellspacing in the css:
table.divCss {border-spacing:0;}

Categories