How to make use of something like Factory in jquery/javascript - javascript

I want to use some good coding standards for the current project. The overall outcome is achievable now (in my project), but i want help regarding following a better approach.
I'll try my best to explain what I am doing.
I have a xml Response for System and Product information (The xml is too big to accomodate here 1MB approx)
I have two panes left Pane (an accordion listing what is to be clicked) right Pane (JQUERY UI TABS inside which is JPANEL accomodating JQGRID inside it)
When the left Pane any item is clicked 3 params are sent, id of the anchor tag, Service Name & an alias (which decides what tab content should be) to function infa9Services(id,sname,alias){...}
<a id="infa9Services"\>DataIntegrationService</a> //this is the Service Name
alias is coming from a map, which maps service Name to a alias DIS (in one case)
The Right Pane contains a <div id="detailTable"></div> which gets populated from infa9Services function.
Content of infa9Services function
var tabs = [ "Service", "Property", "Additional Info" ];
//Above array creates the Jquery Tab heading
var lis="";
var divs="";
var panels=[];
var tpanels="";
var adtrs="";
var service=[];
var property=[];
var aDoctor=[];
var homeFileList=[];
var ssaprlist=[];
var refData=[];
fetching data from xml response xml
$(xml).find('product').each(function(){
$(this).children('DomainMeta').each(function(){
$(this).children('Service').each(function(){
if(sname==$(this).attr('name')) //There are more than one service in the xml, so checking which Service name was clicked, in this case DataIntegrationService
{
$(this).children('OptionGroup').each(function(){
if($(this).attr('name').toLowerCase().indexOf("service") >= 0)
{
$(this).children('Option').each(function(){
var srow={};
srow.name=$(this).attr('name');
srow.value=$(this).attr('value');
service.push(srow);
});
}
else
{
$(this).children('Option').each(function(){
var prow={};
prow.name=$(this).attr('name');
prow.value=$(this).attr('value');
property.push(prow);
});
}
});
}
});
});
Now here I am checking using if else what alias is it, based on which i'll fetch data
if(alias==="PCIS")
{
$(this).children('addressDoctor').each(function(){
$(this).children('addressDoctor_info').each(function(){
//adding xml values to aDoctor array
});
});
$(this).children('homefilelist').each(function(){
$(this).children('homefilelist_info').each(function(){
//adding xml values to homeFileList array
});
});
}
else if(alias==="PCRS")
{
$(this).children('homefilelist').each(function(){
$(this).children('homefilelist_info').each(function(){
//adding xml values to homeFileList array
});
});
}
else if(alias==="DIS")
{
$(this).children('addressDoctorEngVerDIS').each(function(){
adtrs='<tr width="100%">'+
'<th class="thPanel" align="left" valign="top" width="40%">'+$(this).children('addressDoctorEngVer_info').attr('name')+'</th>'+
'<td align="left" width="60%">'+$(this).children('addressDoctorEngVer_info').attr('value')+'</td>'+
'</tr>';
});
}
else if(alias==="CMS")
{
$(this).children('referenceDataLocation').each(function(){
$(this).children('referenceDataLocation_info').each(function(){
//adding xml values to refData array
});
});
$(this).children('ssaprDirList').each(function(){
$(this).children('ssaprDirList_info').each(function(){
//adding xml values to ssaprlist array
});
});
}
});
dynamically adding li 's (for UI tabs)
$.each(tabs, function(i, item) {
lis+='<li>'+item+'</li>';
});
dynamically adding div's with class="class" (for JPanel) is there a better way here?
panels[0]='<div title="General Information" class="class">'+
'<div class="jqUIDiv">'+
'<table id="tblService" width="100%"></table>'+
'<div id="ServiceGridpager"></div>'+
'</div>'+
'</div>';
panels[1]='<div title="General Information" class="class">'+
'<div class="jqUIDiv">'+
'<table id="tblProperty" width="100%"></table>'+
'<div id="PropertyGridpager"></div>'+
'</div>'+
'</div>';
Here again I am making use of if else what alias is it, based on which i'll populate data from the vars which were fetched before
if(alias==="PCIS")
{
panels[2]='<div title="Address Doctor" class="class" >'+
'<table class="jpanelTable">'+
'<tbody>'+adtrs+'</tbody>'+
'</table>'+
'</div>';
panels[2]+='<div title="Address Doctor Configuration" class="class">'+
'<div class="jqUIDiv">'+
'<table id="tblAdditional" width="100%"></table>'+
'<div id="AdditionalGridpager"></div>'+
'</div>'+
'</div>';
panels[2]+='<div title="Home File List" class="class">'+
'<div class="jqUIDiv">'+
'<table id="tblHomeFileList" width="100%"></table>'+
'<div id="HomeFileListGridpager"></div>'+
'</div>'+
'</div>';
}
else if(alias==="PCRS")
{
panels[2]='<div title="Home File List" class="class">'+
'<div class="jqUIDiv">'+
'<table id="tblHomeFileList" width="100%"></table>'+
'<div id="HomeFileListGridpager"></div>'+
'</div>'+
'</div>';
}
else if(alias==="DIS")
{
panels[2]='<div title="Address Doctor" class="class" >'+
'<table class="jpanelTable">'+
'<tbody>'+adtrs+'</tbody>'+
'</table>'+
'</div>';
}
else if(alias==="CMS")
{
panels[2]='<div title="Reference Data Location" class="class">'+
'<div class="jqUIDiv">'+
'<table id="tblRefData" width="100%"></table>'+
'<div id="RefDataGridpager"></div>'+
'</div>'+
'</div>';
panels[2]+='<div title="SSAPR" class="class">'+
'<div class="jqUIDiv">'+
'<table id="tblSSAPR" width="100%"></table>'+
'<div id="SSAPRGridpager"></div>'+
'</div>'+
'</div>';
}
else
{
panels[2]='<div title="Additional Information" class="class" >'+
'<table class="jpanelTable">'+
'<tbody>'+
'<tr width="100%">'+
'<td align="left" style="word-break:break-all;">'+NA+'</td>'+
'</tr>'+
'</tbody>'+
'</table>'+
'</div>';
}
Note: panel[0],panel1,panel[2] are contents of the 3 tabs
dynamically adding div 's (content for Jquery UI Tab)
$.each(panels, function(i, item) {
divs+='<div id="tabs-'+i+'">'+item+'</div>';
});
adding the whole thing to detailTable (Right Pane)
$('#detailTable').empty();
$('#detailTable').html('<div class="titleBlue">Configuration>'+productname+'>'+sname+' ('+alias+')</div>');
$("<div id='loadingDiv'><table id='detailTable' width='100%'><tbody><tr><td align='center'>Please wait</td></tr><tr><td align='center'><img src='/csm/view/include/images/loading.gif' alt='Loading'/></td></tr></tbody></table></div>").appendTo('#detailTable');
$('<div id="tabs">'+'<ul>'+lis+'</ul>'+divs+'</div>').appendTo('#detailTable').delay(10).queue(function(){
$('.class').jPanel({
'effect' : 'fade',
'speed' : 'medium',
'easing' : 'swing'
});
});
More.. JQGrids to populate tblService, tblSSAPR, tblRefData etc tables (not included here)
How can I make use of something like Factory or something more Generic in such a case? If suppose there are a lot of alias to be checked it will be very cumbersome to do it the way I am doing it currently. Any help would be appreciated. Thanks
Screen shot
Update
My XML content
<?xml-stylesheet type="text/xsl" href="csmclientinfa9.xsl"?>
<csmclient product="infa9" date="12/16/11 12:10 PM" version="1.0">
<system>
</system>
<product>
<DomainMeta>
<Service type="PCIntegrationService" name="TestPCInteg" version="" licenseName="lic_PCIS"> //THIS IS PCIS SERVICE
<ServiceProcess>
<Node name="N_1a63931"></Node>
<PreStartCommand> null</PreStartCommand>
<PostStartCommand> null</PostStartCommand>
<JvmOptions> </JvmOptions>
<OptionGroup name="IntegrationServiceProcessOptions">
<Option name="Codepage_Id" value="4" ></Option>
<Option name="$PMSourceFileDir" value="$PMRootDir/SrcFiles" ></Option>
</OptionGroup>
</ServiceProcess>
<OptionGroup name="IntegrationServiceOptions">
<Option name="ServiceResilienceTimeout" value="180" ></Option>
</OptionGroup>
</Service>
<Service type="DataIntegrationService" name="TestDIS" version="" licenseName="lic_DIS"> //THIS IS DIS SERVICE
<ServiceProcess>
<Node name="N_1163931"></Node>
<PreStartCommand> null</PreStartCommand>
<PostStartCommand> null</PostStartCommand>
<JvmOptions> -Dfile.encoding=UTF-8 -server -Xms256M -Xmx512M -XX:GCTimeRatio=19 -XX:+UseConcMarkSweepGC -XX:+UseParNewGC -XX:ParallelGCThreads=4 -XX:NewRatio=2</JvmOptions>
<OptionGroup name="SQLServiceOptions">
<Option name="MaxConcurrentConnections" value="100" ></Option>
<Option name="MaxPlanCacheSize" value="100" ></Option>
</OptionGroup>
<OptionGroup name="WebServiceOptions">
<Option name="MaxPlanCacheSize" value="100" ></Option>
</OptionGroup>
</ServiceProcess>
<OptionGroup name="SQLServiceOptions">
<Option name="ConnectionCleanupPeriod" value="30000" ></Option>
<Option name="DTMKeepAliveTime" value="0" ></Option>
</OptionGroup>
<OptionGroup name="CoreServiceOptions">
<Option name="SafeModeLevel" value="0" ></Option>
</OptionGroup>
</Service>
</DomainMeta>
<homefilelist>
<homefilelist_info permission='-rwxr-xr-x' hardlink='1' owner='idp' group='support' fsize='61597' date='22 Mar 2011' filename='libpmwspsvrcmn.so' />
<homefilelist_info permission='-rwxr-xr-x' hardlink='1' owner='idp' group='support' fsize='21778' date='22 Mar 2011' filename='libpmorablk.so' />
</homefilelist>
<addressDoctor filename='AD100.cfg'>
<addressDoctor_info name='MemoryUsage' value='1048' />
<addressDoctor_info name='PreloadingMethod' value='MAP' />
</addressDoctor>
<addressDoctorEngVerPCIS>
<addressDoctorEngVer_info name='EngineVersion' value='5.2.5' />
</addressDoctorEngVerPCIS>
<addressDoctorEngVerDIS>
<addressDoctorEngVer_info name='EngineVersion' value='5.2.6' />
</addressDoctorEngVerDIS>
<referenceDataLocation location='/home/idp/av/default'>
<referenceDataLocation_info permission='-rw-r--r--' hardlink='1' owner='idp' group='support' fsize='196' month='Aug' date='2' time='11:06' filename='copyright.txt'/>
</referenceDataLocation>
<ssaprDirList>
<ssaprDirList_info permission='-rw-r--r--' hardlink='1' owner='idp' group='support' fsize='2737558' month='Oct' date='14' time='2010' filename='turkey.ysp' />
</ssaprDirList>
</product>
</csmclient>
More Updates
var aDoctor=[];
var adtrs="";
var homeFileList=[];
if(alias==="PCIS")
{
$(this).children('addressDoctorEngVerPCIS').each(function(){
adtrs='<tr width="100%">'+
'<th class="thPanel" align="left" valign="top" width="40%">'+$(this).children('addressDoctorEngVer_info').attr('name')+'</th>'+
'<td align="left" width="60%">'+$(this).children('addressDoctorEngVer_info').attr('value')+'</td>'+
'</tr>';
});
$(this).children('addressDoctor').each(function(){
$(this).children('addressDoctor_info').each(function(){
var adevrow={};
adevrow.name=$(this).attr('name');
adevrow.value=$(this).attr('value');
aDoctor.push(adevrow);
});
});
$(this).children('homefilelist').each(function(){
$(this).children('homefilelist_info').each(function(){
var row={};
isPresent=true;
row.permission=$(this).attr('permission');
row.hardlink=$(this).attr('hardlink');
row.owner=$(this).attr('owner');
row.group=$(this).attr('group');
row.fsize=$(this).attr('fsize');
row.date=$(this).attr('date');
row.filename=$(this).attr('filename');
homeFileList.push(row);
});
});
}
/*moving on for HTML construction, panels[..]
panels[0] is for 1st jquery ui tab
panels[1] is for 2nd jquery ui tab
panels[2] is for 3rd jquery ui tab*/
/*I am also using jqGrid, so I am giving one example for PCIS, how I am using aDoctor array */
if(alias==="PCIS")
{
//Additional Information
if(aDoctor.length>0)
{
jQuery("#tblAdditional").jqGrid({
datatype: "local",
data: aDoctor,
colNames:['Name','Value'],
colModel:[
{name:'name',index:'name', align:"left"},
{name:'value',index:'value', align:"left"}
],
pager : '#AdditionalGridpager',
rowNum:10,
rowList:[10,50,100],
scrollOffset:0,
height: 'auto',
autowidth:true,
viewrecords: true,
gridview: true
});
jQuery("#tblAdditional").setGridParam({rowNum:10}).trigger("reloadGrid");
jQuery("#tblAdditional").jqGrid('filterToolbar',{stringResult: true, searchOnEnter: false, defaultSearch: 'cn'});
}
else //i am displaying none in the table
}
//So now my panel is complete for PCIS, if you refer my question, all code is available :) I know it's really big, but this is my 1st project and I want it to be better than this :) Thanks

The Factory design pattern must have a switch (if/else block or associative array) under the hood anyhow. You won't ever shorten code by using it. The only benefit you'll get here is that you might hide away or separate some of that long code. Returning a function from another function, or returning an array where one of the properties is a function (set in the factory) is about as close as you can get to this pattern in JavaScript. The code sample below show something very much like a factory that is just as good in the JavaScript case, and might be slightly less confusing.
I'm not sure what you mean by Generic. If you're referring to "generics", ala Java or C#, then it won't help you in this scenario. Generics in those languages help you get around static typing and avoid duplicating classes. You're not using classes at all here.
If you're simply trying to avoid repeating yourself, you should look for a functional refactor here. See what repeats, and what doesn't. Figure out how you can loop or map to the stuff that doesn't repeat, and write the code that does repeat only once.
For example, I'd use an associative array to map strings to functions for your big if/else block, and I'd extract that child-looping code into a more generialized function:
function forAll(parentName, childName, action) {
$(this).children(parentName).each(function(){
$(this).children(childName).each(function(){
action();
});
});
}
var aliasToHandlerMap =
{
"PCIS": function() {
forAll('addressDoctor', 'addressDoctor_info', function() {
//adding xml values to aDoctor array
});
forAll('homefilelist', 'homefilelist_info', function() {
//adding xml values to homeFileList array
});
},
"PCRS": function() {
forAll('homefilelist', 'homefilelist_info', function() {
//adding xml values to homeFileList array
});
},
"DIS": function() {
$(this).children('addressDoctorEngVerDIS').each(function(){
adtrs=
'<tr width="100%">'+
'<th class="thPanel" align="left" valign="top" width="40%">'+
$(this).children('addressDoctorEngVer_info').attr('name')+'</th>'+
'<td align="left" width="60%">'+
$(this).children('addressDoctorEngVer_info').attr('value')+'</td>'+
'</tr>';
});
},
"CMS": function() {
forAll('referenceDataLocation', 'referenceDataLocation_info', function() {
//adding xml values to refData array
});
forAll('ssaprDirList', 'ssaprDirList_info', function() {
//adding xml values to ssaprlist array
});
}
};
// Execute the appropriate handler for the particular alias
var handler = aliasToHandlerMap[alias];
handler();
In this case I'd also recommend you name each of those handlers, and build the map using named functions. I just wanted to show you visually how much code compression you get from this.
You should be able to do similar things for your long strings of HTML that you're building. If they follow a general pattern, make a function for them, and extract the parts that change into parameters that you pass in.
And you generally shouldn't be building styles into your elements (e.g. align="left" valign="top" width="40%"). You should use style sheets that apply to those specific items, applying only CSS classes when necessary, so that you to specify that in only one place. That should shorten a lot of the element creation code, and might let you use jQuery DOM creation to avoid messy string concatenation code.
All refactoring of long code boils down to an application of the same principle - find out what repeats, and what doesn't repeat. Extract the part that repeat, and build an iterable or indexable structure out of the part that doesn't repeat.
To start learning how to do generalized refactoring in languages using a Functional Programming style, I suggest you watch the SICP lecture videos. They use LISP, but teach you it while you're watching the videos, and the principles apply to every language out there. That language lends itself extremely well to this type of refactoring, which is why he uses it.
You could also look into CoffeeScript, which allows you to take java code and shrink it into a more compact syntax :) It compiles back into pretty-printed JavaScript, so you don't have to worry about server impact, installing code on client boxes, etc.
Also, check out a few of these links for more reading on general code refactoring:
http://en.wikipedia.org/wiki/Code_refactoring
http://martinfowler.com/refactoring/ (he wrote a book)

I think you are asking for a better way to make your code without having to hard code the html? If that is the case you could use jQuery.template() http://api.jquery.com/jQuery.template/. It's in beta but it should help you by not having to hardcode your html into the javascript.
For my projects we do our templating in PHP and just have jquery do ajax calls if the data or templates need to change.
If this is not what you are looking for can you be more descriptive with your question?

If you are looking at refactoring further you can use the same jPanel to buld tabs using just a simple div markup like you did for accordion just replace your jPanel js file with the latest 1.4 version that will save some markup junk for you and also you have too much of html as strings try using a javascript template engine here

Related

How can I bind multi select list items that have been dynamically added using the .net core framework?

I am using .net core 2.2 Razor Pages to build my current project. I want to be able to have 2 multi-select lists in which I pass values from one list to the other and vice versa. I am able to load the left side list with the values required using binding. I also have the buttons to transfer X amount of selected items to the right side list. This is done using jquery. However when I submit my form and get the OnPostAsync The values from the list on the right side are lost and the ones on the left side are as if they where never removed.
I understand that to dynamically add controls that bind to a property you require adding all the necessary attributes. I have compared the generated html from the left list (generated by .net core) to the right side list (generated by me using jquery) and they are identical so I don't see what attributes might be missing...
Below is a sample of the code I am working with.
```html
<table width="100%">
<tr>
<td rowspan="2" class="role-fromto">
<select asp-for="RolesLeft" asp-items="#(new SelectList(Model.RolesLeft, "Id", "Name"))" class="form-control" multiple>
</select>
</td>
<td class="centered">
<a id="role-add" class="button-pointer">>></a>
</td>
<td rowspan="2" class="role-fromto">
<select asp-for="RolesRight" asp-items="#Model.RolesRight" class="form-control" multiple>
</select>
</td>
</tr>
<tr>
<td class="centered">
<a id="role-remove" class="button-pointer"><<</a>
</td>
</tr>
</table>
```
(Please note there is a submit button as well which performs the OnPostAsync)
The properties that are binding are in my C# code. The left side roles are a list of Role objects while on the right side I made a list of SelectListItem which I will later convert in the OnPostAsync method. The left side list is populated in the OnGetAsync method during loading (I am not putting this code here because it works and I want to avoid confusion of bloat code):
```C#
[BindProperty]
public List<Role> RolesLeft { get; set; }
[BindProperty]
public List<SelectListItem> RolesRight { get; set; } = new List<SelectListItem>();
```
Finally the javascript that runs when I select the >> link to move over the selected items to the right side executes the following code:
```JavaScript
$(document).ready(function () {
$("#role-add").on("click", function () {
moveRoles("RolesLeft", "RolesRight");
});
$("#role-remove").on("click", function () {
moveRoles("RolesRight", "RolesLeft");
});
function moveRoles(from, to) {
var items = $("#" + from + " option:selected").map(function () {
return $(this);
}).get();
for (i = 0; i < items.length; i++) {
$("#" + from + " option[value='" + items[i].val() + "']").remove();
$("#" + to).append($('<option />', {
value: items[i].val(),
text: items[i].text()
}));
}
}
});
```
I'm not sure if I missed anything but if so please let me know and I will update the post to provide more information. How can I get this working properly? I have been able to dynamically generate other types of controls and get it to bind but this one I have not had any success.

generated AngularJS controller usage

Realized that to implement some front-end stuff in my project, it`s better to use a front-end framework, not just a pure JS. Choose AngularJS.
Trying to implement and generated code and stuck with it...
I`ve got this html code generated and and added to the page content on some action,
function Content(i){
var html =
'<div ng-controller="Hello">'+
'<button ng-click="click_btn()">Load Data!</button>'+
'<div class="panel panel-default">'+
'<div class="panel-heading">Items List</div>'+
'<div class="col-sm-8">'+
'<ul>'+
'<li ng-repeat="element in content"> {{ element }} '</li>'+
'</ul>'+
'</div>'+
'</div>'+
'</div>';
var ul = document.getElementById('FullList');
ul.insertAdjacentHTML('beforeend', html);
AddElementAngular(contentString);
}
And the problem is that AngularJS <div ng-controller="Hello"> won't work here. can't get why, because code is successfully added to the page. I'm also tried to add click_btn() action and test the controller call on this action, but still doesn't work.
Here is the controller's code
angular.module('MainPage', [])
.controller('Hello', function($scope, $http) {
alert('jijij');
$scope.click_btn = function() {
alert('fsdfsdfsd');
}
$http.get('/api/getlist?groupID=2').
success(function(data) {
$scope.content = data;
});
});
The page is big to paste it here, but it starts with <html ng-app="MainPage">, so there shouldn't be a problem.
I'm inserted alerts to check, does the code is running. with the dynamic controller load - no. If i just insert controller's code directly in page content - everything works ok.
Controller inserted to the page dynamically only once. If the function Content(i){} call made again - previous controller's code will be removed.
EDIT:
Found a way to inject generated controller to the scope, from here:
http://geevcookie.com/2014/01/compile-dynamic-html-with-angularjs/
function AddElementAngular(html){
var $div = $(html);
$(document.body).append($div);
angular.element(document).injector().invoke(function($compile) {
var scope = angular.element($div).scope();
$compile($div)(scope);
});
}
But still didn't work properly. Code in the controller is executed(
$http.get('/api/getlist?groupID=2').
success(function(data) {
alert(data);
$scope.content = data;
});
i get the [object][Object]... etc in alert. ), but the in-page <li ng-repeat="element in content"> {{ element }} </li> doesn`t work for unknown reason. I just getting '{{ element }}' in HTML content.

Call controller function from HTML dynamically created

I have a controller which have a function called $scope.removePoster and another one inside the same controller who create a table calling $scope.removePoster like this:
for(var i=0; i < 6 && postersNum >= 0; i++){
...
table += '<td align="center">';
table += '<img width="150" height="175" src="../js/librerias/carousel/images/'+$scope.posters[indexPosters]['image']+'"><br>';
table += '<button type="button" class="btn btn-danger" ng-click="removePoster('+$scope.posters[indexPosters]['id']+')">Delete</button>';
table += '</td>';
...
When I add this table in my HTML the button doesn't call this function.
Sounds like you are using for something like this:
<!-- HTML -->
<table>
<tr ng-repeat="poster in posters | limitTo: 6">
<td align="center">
Poster {{poster.id}}
<img width="15" height="18"
ng-src="../js/librerias/carousel/images/{{poster.image}}" />
<button type="button" class="btn btn-danger"
ng-click="removePoster(poster.id)">
Delete
</button>
</td>
</tr>
</table>
// Controller:
$scope.posters = [];
$scope.getPosters = function (url) {
$http.post(url, {'method' : 1}).success(function (data, status) {
$scope.posters = data;
});
};
$scope.removePoster = function (id) {
$scope.posters.some(function (poster, idx) {
if (poster.id === id) {
$scope.posters.splice(idx, 1);
return true;
}
});
};
See, also, this short demo.
Some highlights:
By using ngRepeat on the <tr> element, we instruct Angular to create as many tr elements as necessary based on the content of posters (subject to the filtering (see below)).
Angular's built-in limitTo filter, filter's the posters array and makes only the first 6 items available to ngRepeat. Conviniently enough, when the content of the posters array changes (e.g. after removing an entry), the whole expression gets re-evaluated creating or removing DOM nodes as necessary.
IMPORTANT
The implementation above is not the proper way to handle things in all aspects. It is the cleanest/easiset way to allow you to wrap your head around Angular's way of building a table dynamically.
Specifically, in a "real-world app", you should have a service bring the data from the server and inject the service into the controller to let it gain access to the data.

ExtJS 4.2.1 - Updating XTemplate after store load

I have a bit of a weird situation...
I have a DataView that's backed by a store. However, in the XTemplate, I'm trying to show the quantity of a certain type of JSON record. Each record has a property value pair that denotes its type. For example:
data: [
{ type: 'W' },
{ type: 'A' },
{ type: 'W' },
{ type: 'W' }
]
So there are 3 JSON objects of 'W' and 1 JSON object of type 'A'. The number of 'W' should be displayed in the HTML element with the class 'total-pending'; 'A', in the HTML element with the class 'total-approved.'
My XTemplate:
tpl: Ext.create('Ext.XTemplate',
'<div style="text-align:center">Leave Requests</div>',
'<table cellpadding="0" class="table-wrap">',
'<tr>',
'<td class="x-leave-request approved"><span class="total-approved">0</span>Approved</td>',
'<td class="x-leave-request pending"><span class="total-pending">0</span>Pending</td>'denied">0</span>Denied</td>',
'</tr>',
'</table>'
)
I've read a bit about templates and stores, but I can't seem to figure out how to update those numbers. I tried to add a function callback to store.on('load', function{}) to change the HTML element via Ext.get(Ext.query('span.total-pending')[0]).update(3) but it had no effect.. Any ideas?
I am not sure will help your request but try and share result with us.
Try to make a function to count total values of W and A then call appropiate function inside the XTemplate via this.function()
tpl: Ext.create('Ext.XTemplate',
'<div style="text-align:center">Leave Requests</div>',
'<table cellpadding="0" class="table-wrap">',
'<tr>',
'<td class="x-leave-request approved"><span class="total-approved">{totalw:this.getTotalw()}</span>Approved</td>',
'<td class="x-leave-request pending"><span class="total-pending">{totala:this.getTotala()}</span>Pending</td>'denied">0</span>Denied</td>',
'</tr>',
'</table>'
)
I solved it using the hint that Oguz gave. What I ended up doing was creating an Ext.util.Hashmap instance, whose pairs were status type and total (e.g. <'W', 10>). Then I called:
<tpl for=".">
{[this.updateStatusTotal(values.type)]}
</tpl>
...
updateStatusTotal : function(type) {
var me = this,
map = me.map,
total = map.get(type);
map.put(type, ++total);
}
then later in the code where the <td> elements are, I call:
{[this.getStatusTotal('W')]}
Done :)

Checkboxes are not appearing

The check-box code below is not working for creating check-boxes against each and every folder of tree structure. It is simple java-script and HTML concept of check boxes which I made use of. I want check-boxes to be created for the tree structure against each and every folder(in left hand side ) of the tree hierarchy.
As the moment I am getting the output as a text associated with each and every folder of the tree hierarchy. So is it something I am doing wrong here? If so, kindly suggest me how can I rectify this error.
var tree = new Tree({
model: model,
checkBoxes: true,
persist: false,
branchIcons: true,
branchReadOnly: false,
checkBoxes: true,
nodeIcons: true,
getLabel: function(item) {
if (!item.root)
return '<input type="checkbox" name="'+ item.name +'" id="'+ item.name +'" value="1" /> '+ item.name;
}
}, "tree");

Categories

Resources