How to initialize object properly and start from clean slate? - javascript

I've got this class:
Ext.define('Customer_Portal_UI.FormParameters', {
constructor: function (c) {
Ext.each(this.ParticipantFormParameters, function (field) {
if (field.toFieldSet != null) {
var fieldSetName = c.targetFieldSetPrefix + field.toFieldSet;
field.toFieldSet = fieldSetName;
}
});
},
ParticipantFormParameters: [
{ name: 'service_executive_account_Number', visible: false },
{ name: 'firstname', visible: true, displayText: 'Firstname', toFieldSet: 'GeneralInfoFS', allowBlank: false },
{ name: 'lastname', visible: true, displayText: 'Lastname', toFieldSet: 'GeneralInfoFS', allowBlank: false },
{ name: 'gendercode', visible: true, hasCheckbox: true, displayText: 'Gender', toFieldSet: 'GeneralInfoFS', xtype: 'combo', allowBlank: false },
]
});
If I do this once:
var formParams = Ext.create(Customer_Portal_UI.FormParameters, { targetFieldSetPrefix: 'add' });
console.log(formParams.ParticipantFormParameters[0].toFieldSet);
I will get addGeneralInfoFS.
But if I create this object many times, I'll get addGeneralInfoFS, addaddGeneralInfoFS, addaddaddGeneralInfoFS
What is going on here ? I tried delete formParams but when I initialize an object if the same type again, same problem.
Is it ExtJS or a javascript problem ? I find it weird I need to put effort into simply destroying objects...
EDIT: Ah! I found this in the documentation:
When placing items in the prototype of the prototype, they will be
shared across all instances of the class. Unless you specifically want
to do this, you should only put "primitive" types inside the prototype
definition.
The question now is how to I declare members without them being "in the prototype" ? That's nice, but where does ParticipantFormParameters go exactly then ? I don't want it in the config cause it's dirty, I'll have to drag this huge (the real code has much more items in the array) block of javascript markup everytime I initialize the object ?
I've refactored things in my application with this approach and I'm completely paralized until this works...I cannot unrefactor...
Thank you.

Why do you modify the property ? Use two different variables. This could be the solution :
(...)
Ext.each(this.ParticipantFormParameters, function (field) {
if (field.toFieldSet != null) {
var fieldSetName = c.targetFieldSetPrefix + field.toFieldSetRaw;
field.toFieldSet = fieldSetName;
}
});
},
ParticipantFormParameters: [
{ name: 'service_executive_account_Number', visible: false },
{ name: 'firstname', visible: true, displayText: 'Firstname', toFieldSetRaw: 'GeneralInfoFS', allowBlank: false },

Related

Sencha: How to use data from one file to another

Im new at this sencha thingy and im trying to experiment a bit with it. I've been making some very simple tests and now i've reached the point where i want to pass the data from one file to another. To make it easier to understand im trying to get the data from the following text box to make a simple filter tool.
the textfield has been created in the following piece of code in the file Filters.js
Ext.define('Prj01Filtro.view.main.Filters', {
extend:'Ext.form.Panel',
xtype: 'Filters',
alias: 'form.formFilter',
requires: [
'Prj01Filtros.view.main.FilterController'
],
controller: 'controllerFilter',
items:[
{
margin: '0 0 10 0',
buttons: [
{
xtype: 'textfield',
fieldLabel: 'Filter',
name: 'textFieldSearch'
}, {
name: 'buttonSearch',
text: 'Buscar',
listeners: {
click: 'onClickFilter'
}
}, {
name: 'buttonRemoveFilter',
text: 'X',
listeners: {
click: 'onClickRemove'
}
}
]
}
]
The code of the buttons have been located in a file named FilterController.js
Ext.define('Prj01Filtros.view.main.FilterController',{
extend: 'Ext.app.ViewController',
alias: 'controller.controllerFilter',
onClickFilter: function() {
//Code to apply the filter
},
onClickRemove: function() {
//code to remove the filter
}
})
Finally the code of the table is located in a file named List.js
Ext.define('Prj01Filtros.view.main.List', {
extend: 'Ext.grid.Panel',
xtype: 'mainlist',
plugins: 'gridfilters',
requires: [
'Prj01Filtros.store.Personnel'
],
title: 'Personnel',
store: {
type: 'personnel'
},
columns: [
{ text: 'Name', dataIndex: 'name', align: 'left', filter: {
type: 'string'
}},
{ text: 'Email', dataIndex: 'email', flex: 1, align: 'left', filter: {
type: 'string'
}},
{ text: 'Phone', dataIndex: 'phone', flex: 1, align: 'left', filter: {
type: 'string'
}},
],
listeners: {
select: 'onItemSelected'
},
});
So my goal is to make a function in FilterController.js that can be called from Filters.js which sets the value for the filters applied in the columns of List.js but im kind of stuck on how to set the value property for the filter from the function that i have created. If someone knows how to do it i would appreciate the help. Thanks!
I've tried many things but since im new to sencha im pretty much sure that they were incorrect anyways.
I suggest to study View Models & Data Binding and ViewModel Internals sections of Ext JS documentation. These are among the most powerful features of Ext JS so it good to develop a deep understanding.
For you current question, you need to access the store behind your List view to manage the filters, not the list itself. Once you get the store, you can set / clear the filters with setFilters and clearFilter methods on the store:
store.setFilter([{
property: 'email',
value: '<search term here>',
operator: 'like'
}]);
store.clearFilter();
To easily access the store, define the store in the view model of a view that is above both List and Filters view. This is the important part because this way you can take advantage of inheriting the view model from the container parent. Let's say you have a panel which contains both List and Filters. Define the store in the view model:
stores: {
personnel: {
type: 'personnel'
}
}
Use bind config when assigning the store in your List:
Ext.define('Prj01Filtros.view.main.List', {
...
bind: {
store: '{personnel}'
}
...
});
After all this, you can access the store from the Filters view controller's methods:
onClickFilter: function() {
this.getViewModel().getStore('personnel').setFilters(...);
}
You need the get the value the user entered into the field. You can access it from the controller with querying the textfield component, but you can also do it with the view model.

Bind in button not working in Ext JS

I want the Zulu button to be disabled until the item inside the change function has a newVal set to it. Currently the Zulu button is enabled and this is an issue because I want it to be disabled until a certain condition, ie. item.set('textstuff', newVal); is met.
What is wrong with my code? I used this post: ExtJS 6 - Bind disabled property to new records in a store for some inspiration but still need some help.
title: 'Foo',
xtype: 'Bar',
autoSelect: true,
labelWidth: 150,
listeners: {
change: function(component, newVal, OldVal) {
var view = this.up('uploadthings');
var items = view.getViewModel().getStore('things').data.items;
items.forEach(function(item) {
item.set('textstuff', newVal);
});
view.getViewModel('bindBool', true);
}
}
}, {
items: [{
xtype: 'panel',
buttons: [{
style: 'margin-right: 30px',
text: 'Zulu',
iconCls: 'x-fa fa-upload',
handler: 'xray',
bind: {
disabled: '{bindBool}'
}
}]
}]
or in your ViewModel.Js file you can add formulas and configure your bondbool,
lets say you set the bindbool at the controller : me.getViewModel().set('bindbool', true)
in your ViewModel :
formulas : {
bindbool : {
get : function(get){
var tempVar = get('bindbool'); //--> true because you set it to true
return tempVar == true ? tempVar : false;
}
}
}
By doing this you can control your viewModel outputs,
Goodluck and have fun coding Extjs

How do I hide certain rows in a ui-grid based on its values?

I have a simple UI grid with these options:
$scope.transactionGrid = {
enableSorting : true,
enableColumnResize : true,
enableScrollbars : true,
enablePaginationControls : false,
minRowsToShow : 6,
onRegisterApi : function(gridApi) {
$scope.gridEventsApi = gridApi;
}
};
I want to hide rows which have a specific value, deleted: "y".
$scope.transactionGrid.data = [
{ Name: "First", deleted: "y" },
{ Name: "Second", deleted: "y" },
{ Name: "Third", deleted: "n" },
{ Name: "Fourth", deleted: "n" }
];
Without actually changing the data, can it be filtered out from rows?
One way is to adjust the row-repeater-template to check for some row-specific value and make the row show/hide that way.
I created a Plunkr showcasing a possible solution.
First you need to create your row-value-checker-function:
appScopeProvider: {
showRow: function(row) {
return row.deleted !== 'y';
}
},
Then you adjust their template by adding that check to their row-repeater
$templateCache.put('ui-grid/uiGridViewport',
...
ng-if=\"grid.appScope.showRow(row.entity)\"
...
}
I know you specifically said "without actually changing the data", but assigning a filtered dataset to the grid would not change the dataset, just the data for the grid. Also it might be a relevant and valid solution for other cases like this.
I forked CMR's Plunk to demonstrate this: http://plnkr.co/edit/NntwWb?p=preview
The key part is just adding a filter when assigning the dataset:
$scope.gridOptions = {
data: $scope.myData.filter(function(row) {
return row.deleted !== "y";
})
};
You can hide it by creating cell templates and hide it based on row value for every field:
$scope.transactionGrid = {
enableSorting : true,
enableColumnResize : true,
enableScrollbars : true,
enablePaginationControls : false,
minRowsToShow : 6,
onRegisterApi : function(gridApi) {
$scope.gridEventsApi = gridApi;
}
// Column template definitions:
columnDefs: [
{
name: 'Name',
displayName: 'Name',
cellTemplate : '<div ng-if="row.entity.deleted">{{row.entity.Name}}</div>'
}
]
};
I made a Plunk to demonstrate a viable technique to solve this: https://plnkr.co/edit/XQRC45vaiZCySZYkEGrz?p=preview

Angular using filter to Update?

I wanted to update my model using $filter or some other smart way without having to do multiple for each.
So basically I have my model similar to below:
$scope.projects = [
{
tasks: [
{
name: 'task name',
visible: true,
starred: true
}
],
createdAt: 'something'
},
{
tasks: [
{
name: 'second task name',
visible: true,
starred: false
}
],
createdAt: 'something'
}
]
What I wanted to do is by using $filter or some other way like underscore and so on, to update the content of the variable. So for instance, when I click a button, I'd like to set visible = true only to tasks that are starred.
Anyone have a suggestion on how to achieve that? Is it possible or I would have to do a couple of loops?
Something like:
$filter('filter')($scope.projects, {{starred = true}}).tasks.visible = true
UPDATE
With the help from #jbrown I was able to achieve what I wanted.
Just in case someone needs similar approach, the final solution was as written below:
_.forEach($scope.projectsModel.projects, function(proj){
_.forEach(_.filter(proj.tasks, {starred: true}), function(task){
task.visible = true;
});
});
Using underscore you can use a combination of filter and find to get the results you are looking for.
$scope.filteredProjects = _.filter($scope.projects, function(proj) {
return _.find(proj.tasks, {
visible: true, starred: true });
});

Ext.bind does not see function in ExtJS

I am trying to mod the Portlet example and port it into our program. The code looks like this:
Ext.create('Ext.container.Viewport',{
id: 'app-viewport', //creates viewport
layout: {
type: 'border',
padding: '0 5 5 5' // pad the layout from the window edges
},
onPortletClose: function(portlet) {
this.showMsg('"' + portlet.title + '" was removed');
},
showMsg: function(msg) {
var el = Ext.get('app-msg'),
msgId = Ext.id();
this.msgId = msgId;
el.update(msg).show();
Ext.defer(this.clearMsg, 3000, this, [msgId]);
},
clearMsg: function(msgId) {
if (msgId === this.msgId) {
Ext.get('app-msg').hide();
}
},
items: [{
id: 'app-header',
xtype: 'box',
region: 'north',
height: 40,
html: 'Ext Welcome'
},{
xtype: 'container',
region: 'center',
layout: 'border',
items: [{
id: 'app-options', //Creates the Options panel on the left
title: 'Options',
region: 'west',
animCollapse: true,
width: 200,
minWidth: 150,
maxWidth: 400,
split: true,
collapsible: true,
layout:{
type: 'accordion',
animate: true
},
items: [{
html: content,
title:'Navigation',
autoScroll: true,
border: false,
iconCls: 'nav'
},{
title:'Settings',
html: content,
border: false,
autoScroll: true,
iconCls: 'settings'
}]
},{
id: 'app-portal', //Creates the panel where the portal drop zones are.
xtype: 'mainpanel',
region: 'center',
items: [{
id: 'col-1', //Each column represents a drop zone column. If we add more there are more created and width gets adjusted accordingly
items: [{
id: 'portlet-1',
title: 'Portlet 1',
html: content,
listeners: {
'close': Ext.bind(this.onPortletClose, this)
},{
id: 'portlet-2',
title: 'Portlet 2',
html: content,
listeners: {
'close': Ext.bind(this.onPortletClose, this)
}
}]
},{
id: 'col-2',
items: [{
id: 'portlet-3',
title: 'Portlet 3',
html: content,
listeners: {
'close': Ext.bind(this.onPortletClose, this)
}
}]
},{
id: 'col-3',
items: [{
id: 'portlet-4',
title: 'Portlet 4',
html: content,
listeners: {
'close': Ext.bind(this.onPortletClose, this)
}
}]
}]
}]
}]
});
The problem is that Ext.bind cannot read the onPortletClose function and the browser gives me a:
Uncaught TypeError: Cannot read property 'apply' of undefined error. I checked the stack and essentially in the Ext.bind(fn,scope) the fn is undefined and thus it cannot read the handler function. The difference between my application and in the example is that I add this directly into a JSP's Ext.onReady() whereas in the example all of this is added through a Ext.apply(this, {...}). I'm really confused. I tried all kinds of gimmicks to force the scope on the viewport but it seems that whatever is inside Ext.bind() loses contact with outside or something. I've used Ext.bind() before and it went fine although it was inside an initComponent configuration. Is that mandatory? If no then what is the problem?
It is important to understand the meaning of this here (or in general when working with JavaScript or ExtJS).
In a global context, this refers to the global object, also known as the global window variable. This is the case inside your Ext.onReady function:
Ext.onReady(function() {
console.log(this === window);
// -> true
// because this is the global object
});
In an object context, by default this refers to the owner object of the function (there are ways around it and actually this is exactly want you want do achieve using Ext.bind):
var obj = {
prop: 'My text property',
fn: function() {
console.log(this.prop);
// -> My text property
// because "this" refers to our object "obj"
}
};
Now, this is exactly what makes the difference between your case and the one from the examples.
When using the approach with Ext.onReady this - as pointed out above - will refer to the global object, which of course does not have a function onPortletClose.
When using the approach from the examples, this is accessed from inside of initComponent, which is a member function of your derived viewport class, and therefore this refers to the component instance (= the owning object), which allows you to access your function.
Ext.define('MyViewport', {
extend: 'Ext.container.Viewport',
onPortletClose: function(portlet) {
this.showMsg('"' + portlet.title + '" was removed');
},
initComponent: function() {
console.log(this);
// -> the instance of your viewport class
Ext.apply(this, {
items:[{
xtype: 'panel',
title: 'Portlet 1',
listeners: {
'close': Ext.bind(this.onPortletClose, this)
}
}]
});
this.callParent();
}
});
Side notes
Ext.apply
Ext.apply really just copies all properties from one object to another, so in this case it is just a convenient way of applying all attributes of that object to this with one function call. You could as well just use:
this.items = [...];
Changing the scope of your listeners
You do not need to use Ext.bind when adding listeners to a component, you can simply provide a scope configuration in your listeners object:
listeners: {
close: function() {...},
scope: this
}
External sources
If you want to dive in a little deeper (which I would recommend), you might want to read more about this at the MDN (Mozilla Developer Network).

Categories

Resources