Sencha: Cannot call method 'getHeader' of undefined - javascript

I am try to update the record of a dataview.List from with the data modified from it's associate form.Panel
code:
onListItemTap:function(list,index,target,record,e){
this.getMain().push({
xtype:'userform',
title:record.data.name,
record:record,
listeners:{
hide:function(form){
record.setData(form.getValues());
list.refresh();
}
}
});
},
Code after record.setData(...);list.refresh();
page getting error:
Uncaught TypeError: Cannot call method 'getHeader' of undefined

It seems like there are issue with the sencha touch 2.3.1 that I am using.
I simply comment the grouped=true property in List component. It works.
code:
{
xtype:'list',
id:'list-user',
store:'Users',
itemTpl: new Ext.XTemplate(...),
flex:1,
//grouped:true
}
hope this finding will save time and from frustration for you.

The problem is the method updateHeaderMap List component.
Ext.define('Nerine.override.List', {
override:'Ext.dataview.List',
updateHeaderMap: function() {
var me = this,
headerMap = me.headerMap,
headerIndices = me.headerIndices,
header, i, item;
headerMap.length = 0;
for (i in headerIndices) {
if (headerIndices.hasOwnProperty(i)) {
/* fix bug */
// console.log('aaa', me.getItemAt(i)); return null
// console.log('bbb', me.getItemAt(i).getHeader());
if( !(item = me.getItemAt(i))) {
continue;
}
header = me.getItemAt(i).getHeader();
headerMap.push(header.renderElement.dom.offsetTop);
}
}
}
});

The group headers have no records in the store. This override solves the issue by checking whether the record for which scrollToRecord is called really is in the store. Furthermore it solves the issue that when calling scrollToRecord is done in painted event, it is possible that the headerMap is not yet ready, which means that the pinnedHeader is not correctly updated when using scrollToRecord.
Ext.define("MyApp.override.List", {
override:'Ext.dataview.List',
scrollToRecord: function(record, animate, overscroll) {
var me = this,
store = me.getStore(),
index = store.indexOf(record);
if(index>-1 && index < this.listItems.length) {
this.updateHeaderMap();
this.callOverridden(arguments);
}
}
});

Related

selObj.fireEvent is not a function

We have this function on a js file to pull a menu tree when users click on the parent item:
function menusel(unid)
{
//if its in the array, deactivate it and take it out
var index = inarray(unid,selectedarray);
//first arrange the array
if(index)
{
selectedarray[index] = 0;
}
else
{
//we have restrictions
if(treeRestrictMode==1)
{
//now check its not in the array of items not allowed to b picked
if(inarray(unid,nonSelArr))
{
alert('This Item is Unselectable');
return;
}
}
//if we are in unique tree mode, can only select one
if(treeSingleMode==1)
{
//check for a non zero value, and deselect it [recursively]#
for(var x=0;x<selectedarray.length;x++)
{
if(selectedarray[x]!=0)
{
//alert(unid+' '+selectedarray[x]);
menusel(selectedarray[x]);
}
}
}
selectedarray.push(unid);
}
sel_unselect(unid,index);
//if we have an override function, it means we will assume that the parent page
//as an input type function called treeSelFunc which takes the id and takes care of the rest
if(overrideFunction!='')
{
parent.parent.treeSelFunc(unid,selName);
return;
}
if(treeSingleMode!=1)
{
var selObj = emptySel(0);//set txt will fill it for us
}
else
{
var selObj = parent.parent.MM_findObj(selName);
//see if we have options..will need to empty them
if(selObj.size>1)
{
emptySel(1);
}
else
{
selObj.value=0;
}
}
setTxt(selObj);
selObj.fireEvent('onchange');
}
which we call like this on a page as this:
<a id="troot[VMENU]_040" onclick="menusel(40);" class="sel">All</a>
And we are getting this:
Uncaught TypeError: selObj.fireEvent is not a function
It used to work on an older browser version (I think with explorer 8) but now is not working any more using Chrome. Any ideas why?
The fireEvent method is a proprietary Microsoft Internet Explorer alternative to the standard EventTarget.dispatchEvent() method.
Use the dispatchEvent method instead.
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent

Plain javascript ScrollTop is not working

When I get a new message or send a new message chat should scroll down. I handle that with this watcher (I update random value in Vuex and watch for changes within component for chat):
watch: {
scrollChatDown: function (val) {
if (this.$refs.chat !== undefined) {
this.$refs.chat.scrollTop = 9999999999999999999999
console.log('WORKING!')
}
}
}
I get this console.log in Mozilla but scrollTop is not working, is there any other solution for this? :D
See this one, uses the current height to scroll down
watch: {
scrollChatDown: function (val) {
if (this.$refs.chat !== undefined) {
this.$refs.chat.scrollTop = this.$refs.chat.scrollHeight
console.log('WORKING!')
}
}
}

Updating Knockout viewModel

I'm attempting to update a knockout view model, but each time I try to push to an observable array it gives me an error that AuditViewModel is undefined.
function (data, update) {
if (update == false) {
var AuditViewModel = {
auditEvents: ko.observableArray(data.requirements)
};
ko.applyBindings(AuditViewModel);
} else {
AuditViewModel.auditEvents.push(data.requirements);
}
}
On the page load this function always runs with update == false, and that originally populates the view model. When I later call with update ==true then it fails. Can someone point me in the right direction?
Note that the line var AuditViewModel = { ... } is only executed if update == false. Because AuditViewModel is a local variable, if you later call the function when update == true, AuditViewModel will be undefined.
You will need to store the view model elsewhere, ie: window.AuditViewModel = { ... }.
Example:
function (data, update) {
if (update == false) {
window.AuditViewModel = {
auditEvents: ko.observableArray(data.requirements)
};
ko.applyBindings(window.AuditViewModel);
} else {
window.AuditViewModel.auditEvents.push(data.requirements);
}
}

Subscribe to observable array for new or removed entry only

So yes I can subscribe to an observable array:
vm.myArray = ko.observableArray();
vm.myArray.subscribe(function(newVal){...});
The problem is the newVal passed to the function is the entire array. Is there anyway I can get only the delta part? Say the added or removed element?
As of KnockoutJS 3.0, there's an arrayChange subscription option on ko.observableArray.
var myArray = ko.observableArray(["Alpha", "Beta", "Gamma"]);
myArray.subscribe(function(changes) {
// For this example, we'll just print out the change info
console.log(changes);
}, null, "arrayChange");
myArray.push("newitem!");
In the above callback, the changes argument will be an array of change objects like this:
[
{
index: 3,
status: 'added',
value: 'newitem!'
}
]
For your specific problem, you want to be notified of new or removed items. To implement that using Knockout 3, it'd look like this:
myArray.subscribe(function(changes) {
changes.forEach(function(change) {
if (change.status === 'added' || change.status === 'deleted') {
console.log("Added or removed! The added/removed element is:", change.value);
}
});
}, null, "arrayChange");
Since I couldn't find any info on this elsewhere, I'll add a reply for how to use this with TypeScript.
The key here was to use the KnockoutArrayChange interface as TEvent for subscribe. If you don't do that, it'll try to use the other (non-generic) subscribe and will complain about status, index, and value not existing.
class ZoneDefinition {
Name: KnockoutObservable<String>;
}
class DefinitionContainer
{
ZoneDefinitions: KnockoutObservableArray<ZoneDefinition>;
constructor(zoneDefinitions?: ZoneDefinition[]){
this.ZoneDefinitions = ko.observableArray(zoneDefinitions);
// you'll get an error if you don't use the generic version of subscribe
// and you need to use the KnockoutArrayChange<T> interface as T
this.ZoneDefinitions.subscribe<KnockoutArrayChange<ZoneDefinition>[]>(function (changes) {
changes.forEach(function (change) {
if (change.status === 'added') {
// do something with the added value
// can use change.value to get the added item
// or change.index to get the index of where it was added
} else if (change.status === 'deleted') {
// do something with the deleted value
// can use change.value to get the deleted item
// or change.index to get the index of where it was before deletion
}
});
}, null, "arrayChange");
}
In order to only detect push() and remove() events, and not moving items, I put a wrapper around these observable array functions.
var trackPush = function(array) {
var push = array.push;
return function() {
console.log(arguments[0]);
push.apply(this,arguments);
}
}
var list = ko.observableArray();
list.push = trackPush(list);
The original push function is stored in a closure, then is overlayed with a wrapper that allows me do do anything I want with the pushed item before, or after, it is pushed onto the array.
Similar pattern for remove().
I am using a similar but different approach, keep track whether an element has been instrumented in the element itself:
myArray.subscribe(function(array){
$.each(array, function(id, el) {
if (!el.instrumented) {
el.instrumented = true;
el.displayName = ko.computed(function(){
var fn = $.trim(el.firstName()), ln = $.trim(el.lastName());
if (fn || ln) {
return fn ? (fn + (ln ? " " + ln : "")) : ln;
} else {
return el.email();
}
})
}
});
})
But it is really tedious and the pattern repeated across my code
None that I know of. Wanna know what I do? I use a previous variable to hold the value, something called selectedItem
vm.selectedItem = ko.observable({});
function addToArray(item) { vm.selectedItem(item); vm.myArray.push(item); }
So that way, when something happens to my observable array, I know which item was added.
vm.myArray.subscribe(function(newArray) { var addedItem = vm.selectedItem(item); ... }
This is really verbose, and assuming your array holds many kinds of data, you would need to have some sort of flags that helps you know what to do with your saved variables...
vm.myArray.subscribe(function(newArray) {
if ( wasUpdated )
// do something with selectedItem
else
// do whatever you whenever your array is updated
}
An important thing to notice is that you might know which item was added if you know whether push or unshift was used. Just browse the last item of the array or the first one and voila.
Try vm.myArray().arrayChanged.subscribe(function(eventArgs))
That has the added value when an item is added, and the removed value when an item is removed.

Difficulty developing unique dynamic onclick events in Javascript

I am working with a decent sized set of data relating to objects on the page and some objects need links applied to them onclick. The link to connect to is part of the dataset and I build a string for the link with the variable linkTarget and apply it like so.
if (dataTag[i][3]==true){
if(prepend==undefined || prepend=="undefined"){
var linkTarget=ResultsJSON["targetUrl"];
ele.onclick = function(){
window.open(linkTarget);
};
} else {
var linkTarget=prepend+ResultsJSON["targetUrl"];
ele.onclick = function(){
window.open(linkTarget);
};
}
ele refers to an element picked up with getElementByID. Now I am going through quite a few objects and the problem I have is the onclick for every object is the last value of linkTarget. This is all contained in a function and link target is a local variable so I have no idea why. I have tried using an array with something like
ele.onclick=function(){window.open(linkTarget[linkTarget.length-1]);};
and even
ele.onclick=function(){window.open(linkTarget.valueOf());};
with the same results. I am at a loss now and would appreciate any help.
Use Array.forEach() to iterate your data and watch your troubles melt away.
dataTag.forEach(function (item) {
if (item[3]==true) {
var linkTarget = "";
if (prepend==undefined || prepend=="undefined") {
linkTarget = prepend;
}
linkTarget += ResultsJSON.targetUrl;
ele.onclick = function () {
window.open(linkTarget);
};
}
});
See this compatibility note for using Array.forEach() in older browsers.
You're in a loop — therefore, you need to put your things-to-be-executed in another function, like so:
if(dataTag[i][3]) {
if(prepend) {
(function(linkTarget) {
ele.onclick = function() {
window.open(linkTarget);
};
})(ResultsJSON.targetUrl);
} else {
(function(linkTarget) {
ele.onclick = function() {
window.open(linkTarget);
};
})(ResultsJSON.targetUrl);
}
I also made some general corrections.

Categories