I'm working on an app in Backbone and am trying to implement Backgrid.js, but I keep getting this error:
Uncaught TypeError: Object function (a){return new m(a)} has no method 'omit'
This occurs when the Backgrid.Grid is initializing and seems to be related to the columns. I have checked my syntax and even created a simplified column array with 1 item and a simplified collection object, with a single attribute matching the column.
var columns = [{name: 'year', label: 'Year', cell: 'string'}];
var data = [{year: '1964'}, {year: '1965'}];
My grid is initialized with:
var grid = new Backgrid.Grid({ columns: columns, collection: data});
Pretty simple and straightforward, but I am still getting this error. I have also checked my versions of Backbone, Underscore and they match what is included in the Backgrid.js download.
Anybody else come across this or have any ideas what might be causing the issue?
There's only one omit call in Backgrid:
var passedThruOptions = _.omit(options, ["el", "id", "attributes",
"className", "tagName", "events"]);
and _.omit was added in Underscore 1.4.0 last September:
1.4.0 — Sept. 27, 2012
[...]
Added an omit function, for filtering an object to remove certain keys.
So presumably you're using a version of Backgrid that expects at least Underscore 1.4.0 but your actually using an older version of Underscore. Try upgrading Underscore (and Backbone while you're at it) to the latest version.
Related
I am using ExtJS 6 (although from what I can tell it applies up to version 7.4 as well) and I have a grid with a booleancolumn xtype. For that boolean column I wanted to use the filter list option. Yes I know there is a boolean filter option however I don't like how it works using a radio button. I wanted to be able to select the Yes or No with checkboxes, however I found that only the option with true as the value worked. Here is my column config:
{
header: 'Active'
, dataIndex: 'inactive'
, xtype: 'booleancolumn'
, trueText: 'No'
, falseText: 'Yes'
, filter:{
type: 'list',
options: [[true,"No"],[false, "Yes"]]
}
}
This didn't work when excluding the 'options' property and letting it get the data from the store either by the way. After looking through the code I discovered that it takes the 'options' config and creates its own Ext.Data.Store using that as the data. See here as a simple example that can be run that will get the same issue:
var teststore = new Ext.data.Store({
fields: [
'id',
'text'
],
data: [[true,"No"],[false, "Yes"]]
});
The problem is that the 'false' boolean value is changed and is replaced with a dynamically created generic id. I discovered the issue lays in the constructor for 'Ext.data.Model' for the following line:
if (!(me.id = id = data[idProperty]) && id !== 0) {
If that line evaluates to true it will replace the id with the generated one. To fix this I just added ' && id !== false' to the end of the if statement and this fixed the issue.
I have not tested this fully, however the logic seems sound and it looks like the same type of issue occurred with the value of '0' hence the ' && id !==0'. Since we are directed here from the sencha forums I wanted to bring this up in case it helps someone.
Since my post already has the answer I will post a better way to do it other than directly changing the Ext code file (whether this is the proper way I may be wrong). Instead, you can create a new js file that will need to be included in your application (you can name it ext-overrides.js). In the new js file you need only type:
Ext.override(Ext.data.Model, {
constructor: function(data, session) {
.....
}
}
You would then copy the constructor function code from your version of the ExtJS code in where the '.....' is (if perchance the constructor function arguments are different you would have to update those as well) and just add the suggested change I made above in the 'question'. A search of the Extjs code for Ext.define('Ext.data.Model' should get you there easily and then just scroll to the constructor function.
I need to get a list of all Features that belonged to a specific Release on a specific date. I know basically how to use the lookback API and I can use it get the Release object for the specific date. The problem is the Release Object doesn't seem to contain a Children element. This is according to the official documentation.
So I tried pulling all of the features for the whole project in hopes of being able to filter by Release.ObjectID, but anytime I try to filter by Release.ObjectID the response is null. Not an empty array indicating no matching records but actual null. I have probably tried a dozen different ways.
This is how the code looks now, with all attempts to filter by Release.ObjectID removed. Can anyone point out how to get this done as part of the query, or am I going to have to load all of the features and then manually filter them?
_lookbackFeaturesByRelease: function(){
var scope = this.getContext().getTimeboxScope()
var ReleaseID = scope.record.raw.ObjectID;
var ProjectID = this.getContext().getProject().ObjectID;
this.snapshot = Ext.create('Rally.data.lookback.SnapshotStore', {
autoLoad: true,
limit: Infinity,
params: [removeUnauthorizedSnapshots = 'true'],
find: {
_ProjectHierarchy: ProjectID,
_TypeHierarchy: "PortfolioItem/Feature",
__At: "2017-02-10T00:00:00Z"
},
fetch: ['ObjectID', 'Name', 'Release'],
hydrate: ['Release'],
listeners: {
load: this._processlbR,
scope: this
} //End Listeners
});//End snapshot create
},//End _lookbackRelease
I think you can just add something like this to your find:
find: {
Release: { '$in': [12345, 23456] }
}
Where 12345 and 23456 are the release objectid's that correspond to your selected release and releases in child projects. You'll need to query wsapi to find all the release oids in your current project scope and pass those values.
I assume I am doing something silly and clearly wrong, but I am baffled. Using CoffeeScript and marionette backbone, I want to create a methods on my collection that will set most models to selected and then set all selected to unselected. I assumed
deselectAll: ->
#where({selected: true})
would get me the selected models and I could iterate over that (for model in selected) and set the models. But I cannot get #where to work and instead get:
Uncaught TypeError: _.matches is not a function
from backbones:
where: function(attrs, first) {
var matches = _.matches(attrs);
return this[first ? 'find' : 'filter'](function(model) {
return matches(model.attributes);
});
},
UPDATE
It is currently working with filter:
#filter (model) ->
model.get 'selected'
and it seems somewhat more complicated than where was, but perhaps not?
backbone <= 1.2.1 is not compatible with underscore >= 1.8.0. Upgrade your backbone to 1.2.2 or 1.2.3.
In underscore 1.8.0 function matches is deprecated and renamed to matcher. See underscore changelog
I'm trying to create a dry search results model and collection for backbone so that no matter what I'm searching for in the app, we use the same model/collection and occasionally might call a different view.
My Model and controller are very simple
Myapp.Models.Search = Backbone.Model.extend();
Myapp.Collections.Search = Backbone.Collection.extend({
model: Myapp.Models.Search
});
I then populate the url value to get the correct requests and parameters in the view
Myapp.Views.SearchResults = Backbone.View.extend({
el: 'div#results',
initialize: function(){
Myapp.results = new Backbone.Collection.Search;
Myapp.results.url = this.model.search_type+'/'+this.model.data; //this holds the search query
Myapp.results.fetch({
success: function(){alert('got result')},
error: function(){alert('that is not good!');}
});
}
without 'fetch', everything is fine, but when I include fetch, the fetch is made, the results are returned, but I get the error
Uncaught TypeError: undefined is not a function in backbone.js:23
I've checked the response, and it is valid JSON. When I output the Myapp.results to the console, I see the collection, but it is still empty. Neither the error not success are getting gtriggered.
----------------update------------------------
as per the comments, I've divided up line 23, and found that the error is being returned in this line
a=new this.model(a,b),
If I am understanding what this line does, could this issue be because the response collection only has one model being returned? I would hope that wouldn't cause the issue, you should be able to have a collection with 1 or less models in it.
--------------update--------------------------
So I remove the reference to model within the collection, and now I don't get the error. So in some ways, this is resolved, but it shouldn't be. Is there a reason why up to now I've always defined the model associated with the collection?
ExtJS Model fields have mapping option.
fields: [
{name: 'brandId', mapping:'brand.id', type: 'int'},
{name: 'brandName', mapping:'brand.name', type: 'string'},
The problem is: if the response from server does not contain some field(brand field in my example) and mapping from inner fields is defined, Ext Store silently fails to load any records.
Does anybody have problems with this? Is it some kind of a bug?
UPDATE
To make it clear: suppose I have ten fields in my model. Response from server has nine fields, one is missing. If there is no nested mapping for this field (mapping:'x.y.z') everything is OK - store loads record, the field is empty. But if this field has to be loaded from some nested field and has mapping option - store fails to load ANYTHING.
UPDATE 2
I have found the code, that causes problems. The fact is: when Ext tries to load some field from Json it performs a check like this
(source["id"] === undefined) ? __field0.defaultValue : source["id"]
But when field has mapping option(mapping 'brand.id') Reader does it this way
(source.brand.id === undefined) ? __field20.defaultValue : source.brand.id
which causes error if source has no brand field.
In case you have same problems as I: you can fix it by overloading Ext.data.reader.Json's method createFieldAccessExpression
I agree that Ext should only fail to load that field, not the entire record. One option that isn't great, but should work, is instead use a mapping function:
{
name: 'brandId',
mapping: function(data, record) {
return data.brand && data.brand.id;
}
}
I could have the arguments wrong (I figured out that this feature existed by looking at the source code), so maybe put a breakpoint in there to see what's available if it doesn't work like this.
I think you're misinterpret mapping and nesting paradigms: these are not interchangeable.
If you define nesting in your data, the result MUST have the corresponding field.