I am trying to delete a model that I create in backbone. I am not trying to do away with the model itself.
this is what I have: A jasmine unit test to the code first
it("should delete the current Box ", function () {
var myContainer = new App.Container();
var myBox = new App.Box();
myBox.setTitle("The First Box");
expect(myBox.attributes.title).toBeDefined();
**myContainer.deleteBox(myBox);**
expect(myBox.attributes.title).toBeUndefined();
});
Now the code:
App.Container = Backbone.Model.extend({
defaults: {
type: "1.0",
selectedBox: 0,
boxes: [],
labels: [],
},
deleteBox: function () {
this.destroy({
success: function() {
console.log("the box has been removed");
//Array reindexed
}
});
}
});
It does not work. the jasmine unit test fails and I think I have to some how delete the object at the cid given by backbone. Im not sure how to go about it. any suggestions?
It looks like you are misusing a Backbone Model in your use of Container. It would be much better practice to make the box a view that has its own model, and the container a view that has a Box Collection assigned to it and iterates through creating and then managing your boxes. You can assign listeners to the collection to choose when to delete a box.
You call myContainer.deleteBox(myBox);, but then don't receive the box passed as a parameter!
UPDATE
In response to your note, I do understand - it does take some head-wrapping to get used to the concepts in Backbone.
If I understand what you are trying to do, here's some sample code that you can chew on that gives a bit of a better idea of how to accomplish this kind of thing:
App.Boxes = Backbone.Collection.extend({})
App.Box = Backbone.View.extend({}); // Child view for each model
App.Container = Backbone.View.extend({ // 'Collection view', that draws
// each child view.
tagName: 'div',
initialize: function(){
this.boxes = {};
// Assign event listeners to redraw DOM when your models change.
this.listenTo(App.boxes, 'add', this.addBox);
this.listenTo(App.boxes, 'remove', this.removeBox);
},
// Create a new box when a new model is added to the collection.
addBox: function(model) {
var newBox = new App.Box({ model: model });
this.boxes[model.cid] = newBox;
this.$el.append(newBox.render().el);
},
// Remove a box when a model is removed from the collection.
removeBox: function(model) {
var box = this.boxes[model.cid];
box.remove();
},
});
// Let's make the parent view.
var myContainer = new App.Container();
$(body).append(myContainer.render().el);
// Make a new collection
App.boxes = new App.Boxes();
// Add models to the collection
App.boxes.add({ title: 'The First Box', });
App.boxes.add({ title: 'The Second Box', });
// Remove a model from the collection.
App.boxes.findWhere({ title: 'The First Box' }).remove();
Does this help?
Related
I've a table specifying the roles and actions, if I check in the role and press delete button, then I should get a dialog box indicating that specific role
If I click on add button, I should get a dialog box or message box with the list of few other roles and on clicking on that role, a rolename should be displayed that has to be added to the respective table
I've created the sap.m.Table and I'm binding the JSON data
Enclosed the Image of the UI:
I've tried with various methods and I'm enclosing my code
Here is the code..
I can delete the item from the table, but I should get a dialog/message box indicating that, the checkmarked role in the table has been deleted
<script>
function delete1()
{
var v = false;
$('input[type="checkbox"]:checked').each(function() {
v = true;
alert("Checked item in the table will be deleted from the table");
});
if (v == false)
{
alert("Please check the item to be deleted");
}
$('input[type="checkbox"]:checked').closest("tr").remove();
}
var oModel = new sap.ui.model.json.JSONModel("JSon/etc5.json");
// Load JSON in model
sap.ui.getCore().setModel(oModel,"model1");
//create table
//"cells"
var oRoles = new sap.m.Text({text: "{model1>Role}"});
var oAction = new sap.m.Button({text: "DETAILS",
type : sap.m.ButtonType.Emphasized,
});
// corresponding columns
var oColAbbr = new sap.m.Column({header: new sap.m.Text({text:"ROLES"}) });
var oColAct = new sap.m.Column({header: new sap.m.Text({text:"ACTION"}) });
// row template
var oRow = new sap.m.ColumnListItem();
oRow.addCell(oRoles).addCell(oAction);
// instantiating the table
var oTab = new sap.m.Table("app",{
inset : true,
headerText : "SOME DATA",
headerDesign : sap.m.ListHeaderDesign.Standard,
includeItemInSelection : false,
});
oTab.addColumn(oColAbbr).addColumn(oColAct);
oTab.bindItems("model1>/emp", oRow); //binding data to the tables
oTab.setMode(sap.m.ListMode.MultiSelect);
var oButton = new sap.m.Toolbar({
content: [
new sap.m.ToolbarSpacer(),
new sap.m.Button({
text : "ADD",
textAlign : "Center",
width : "10%",
type: sap.m.ButtonType.Emphasized,
press: function() {
// oCDialog2.open();
},
}),
new sap.m.Label({text:""}),
new sap.m.Button({
text : "DELETE",
textAlign : "Center",
width : "10%",
type: sap.m.ButtonType.Reject,
press: function() {
// oCDialog1.open();
delete1();
}
}),
]
});
//creating the icons
var iTab = new sap.m.IconTabBar({
items:[
new sap.m.IconTabFilter({
text: "HR",
icon: "sap-icon://group",
content:[oTab]
}),
]
});
var page = sap.m.Page({
content: [iTab,oButton],
showHeader : false,
enableScrolling : true,
});
var app = sap.m.App();
app.addPage(page);
app.placeAt("content");
</script>
It is probably easiest to use the Checkbox control and bind it's value to the same model as where the item lines come from (model1>/emp). In your delete method, you could then easily iterate through the emp array and test on the value representing the checkbox.
Whenever you delete an entry from the array, either UI5's MessageToast or MessageBox controls to show the message. Alerts may be blocked by "Check here to disable alerts from this website" functionality in some browsers.
You may also want to change the $.each to a $.grep instead. This loops through an array in pretty much the same way as $.each with one exception. If you return true from the callback, the element is retained. Otherwise, it is removed from the array.
Your code should look something like this:
items = this.getView().getModel("model1").getProperty("/emp");
items = $.grep(items, function (el, i) {
if (el.propertyBoundToCheckbox) {
MessageToast.show("Deleting entry: " + el.getName())
return false;
}
return true; // keep the element in the array
});
Note: The code above pulls the model from the view, as that's a best practice. Try not to tie anything to the core, as the core is shared between all applications running in the browser window (e.g. in Fiori Launch Pad scenario).
I have a situation where I need to dynamically add or remove grids selection model.
Searching the documentation I see that the selection model doesn't have a destroy() method or anything similar. How can I remove or destroy a selection model from a grid in ext js 4.x.?
If this is not possible I still have an option to revert some functionallity and dynamically add the selection model to an already created grid. But I'm also not sure if this is possible.
I'd suggest to disable the selection model instead of destroying it.
You can clear the current selection (deselectAll) and lock the selection model to prevent further selection (setLocked):
selModel.deselectAll();
selModel.setLocked(true);
As you're using a checkbox selection model, you'll also need to hide the corresponding column which is added to the grid:
grid.headerCt.child('gridcolumn[isCheckerHd]').hide();
Selection models are not designed to be replaced, so... it's gonna be complicated!
You'd have to reproduce the initialization of the sel model, unwire the previous one, and rewire the new one...
Here's an example that works in substituting a row selection model for a checkbox model. It may still contains memory leaks from listeners registered by the first selection model that I would have forgot. The creation of the new selection model relies on the getSelectionModel method of the grid, which implements the disableSelection, simpleSelect, and multiSelect options of the grid (see the code).
Ext.widget('grid', {
renderTo: Ext.getBody()
,store: ['Foo', 'Bar', 'Baz']
,selType: 'checkboxmodel'
,columns: [{
dataIndex: 'field1'
,text: "Name"
}]
,listeners: {
selectionchange: function(sm, records) {
var grid = sm.view.up(),
item = grid.down('tbtext');
if (records.length) {
item.setText(
'Selection: ' + Ext.pluck(Ext.pluck(records, 'data'), 'field1').join(', ')
);
} else {
item.setText('No selection');
}
}
}
,tbar: [{
text: "Replace selection model"
,handler: function(button) {
var grid = button.up('grid'),
headerCt = grid.headerCt,
checkColumn = headerCt.down('[isCheckerHd]'),
view = grid.view,
previous = grid.selModel,
sm;
// try to clean up
previous.deselectAll();
previous.destroy();
// sel model doesn't clear the listeners it has installed in its
// destroy method... you'll have to chase the listeners that are
// installed by the specific type of sel model you're using
if (previous.onRowMouseDown) {
view.un('itemmousedown', previous.onRowMouseDown, previous);
}
if (previous.onRowClick) {
view.un('itemclick', previous.onRowClick, previous);
}
// clear references
delete grid.selModel;
delete view.selModel;
// create another selModel
grid.selType = 'rowmodel';
//grid.disableSelection = true;
sm = grid.getSelectionModel();
// assign new sel model
view.selModel = sm;
sm.view = view;
// remove checkbox model column
if (checkColumn) {
headerCt.remove(checkColumn);
}
// init sel model is trigerred in view render events, so we must do it
// now if the view is already rendered
if (view.rendered) {
sm.beforeViewRender(view);
sm.bindComponent(view);
}
// finally, refresh the view
view.refresh();
}
}]
// a place to display selection
,bbar: [{
xtype: 'tbtext'
,text: 'No selection'
}]
});
I have stored some data on local storage. I read data on localstorage with
localStorage.getItem('students');
The read from local storage results
[
{
"studentName":"John",
"rollno":"12",
"address1":"add1",
"address2":"add2",
"city":"Jackson Height",
"state":"New York",
"zip":"0111"
},
{
"studentName":"Mohan",
"rollno":"13",
"address1":"add3",
"address2":"add5",
"city":"Mackson Height",
"state":"New york",
"zip":"004"
}
]
I am using backbone and underscore. I want to generate html as follows with underscore template from above student json data from local storage and hook it to some
<ul>
<li ><strong>Appointments</strong></li>
//I want to create list from here from student data from localstorage
<li>student name 1 rollno</li>
<li>student name 2</li>
</ul>
How can I do this? Also, i wanted each list to be some model or something so that when i click on it, it allows me to go some view that will display all fields in students.Do in need to create model or collection though i take data from local-storage?
eh... this is a little complicated if you want make every "li" as a view. This is my solution:
You need a super-view to hold the ul, and create sub-views as many as you want in this super-view.
// this is the sub view, it's stand for every student
var SubView = Backbone.View.extend({
// every student's name display in a li
template: _.template('<li><%= obj.studentName %></li>'),
// let every sub view react click event
events: {
'click': 'showDetail'
},
// draw li
render: function() {
// model will be passed in went sub view was created, and sub view append to ul
this.$el.html(this.template(this.model.toJSON())).appendTo('.ul');
},
showDetail: function() {
// here is your function to show student's detail
// note you got the student data when this view was create
// so you can refer it with this.model
}
});
// this is the super view
var SuperView = Backbone.View.extend({
// catch ul, i assume it is the only one ul exists on your page
el: $('ul'),
// run on super view was createc
initialize: function() {
// get your students
var students = localStorage.getItem('students');
// loop through students
_.each(students, function(student) {
// create sub view(li) for every student
var subView = new SubView({
// a little tricky here, wrap your student data into model
// and pass it (or say save it) in every sub view
model: new Backbone.Model.extend(student);
});
// render the sub view
subView.render();
});
}
});
after all this, just do "new SuperView()". and should be what you want.
this code is just an idea, I didn't run it actually.
I have a question about the way backbone handles it views.
Suppose I have the following code:
<div id="container">
<div id="header">
</div>
</div>
After this I change header into a backbone view.
How can I now remove that view from the header div again after I'm done with the view and add ANOTHER view to the same div?
I tried just overwriting the variable the view was stored in. This results in the view being changed to the new one...but it will have all the event handlers of the old one still attached to it.
Thanks in advance!
http://documentcloud.github.com/backbone/#View-setElement
This won't automatically remove the original div - you'll want to do that yourself somehow, but then by using setElement you'll have the view's element set to whatever you passed it.. and all of the events will be attached as appropriate. Then you'll need to append that element wherever it is that it needs to go.
--- Let's try this again ----
So, first thing to keep in mind is that views reference DOM elements.. they aren't super tightly bound. So, you can work directly with the jquery object under $el.
var containerView = new ContainerView();
var headerView = new HeaderView();
var anotherHeaderView = new AnotherHeaderView();
containerView.$el.append(headerView.$el);
containerView.$el.append(anotherHeaderView.$el);
anotherHeaderView.$el.detach();
containerView.$el.prepend(anotherHeaderView.$el);
Or you can create methods to control this for you.
var ContainerView = Backbone.View.extend({
addView: function (view) {
var el = view;
if(el.$el) { //so you can pass in both dom and backbone views
el = el.$el;
}
this.$el.append(el);
}
});
Maybe setting the views by view order?
var ContainerView = Backbone.View.extend({
initialize: function () {
this.types = {};
},
addView: function (view, type) {
var el = view;
if(el.$el) { //so you can pass in both dom and backbone views
el = el.$el;
}
this.types[type] = el;
this.resetViews();
},
removeView: function (type) {
delete this.types[type];
this.resetViews();
},
resetViews: function () {
this.$el.children().detach();
_.each(['main_header', 'sub_header', 'sub_sub_header'], function (typekey) {
if(this.types[typekey]) {
this.$el.append(this.types[typekey]);
}
}, this);
}
});
In my MVC application in Controller i have following function to add and focus new tab to TabPanel with DataView inside:
show_gallery: function(view, record, item, index, e, opts) {
var tabb = Ext.ComponentQuery.query('.gallery_panel');
var gallery_view = Ext.widget('gallery_view');
var ImageStore = Ext.create('Gallery.store.Images');
ImageStore.load({url: 'myphoto/index.php/api/feed/json/' + record.data.uuid});
Ext.apply(gallery_view, {
title: record.data.name,
id: record.data.uuid,
closable:true,
store: ImageStore
});
if (tabb[0].down('#' + record.data.uuid)) {
console.log('Entered IF');
//tabb[0].setActiveTab(tabb[0].down('#' + record.data.uuid));
tabb[0].setActiveTab(record.data.uuid);
}else{
console.log('Entered ELSE');
tabb[0].add(gallery_view);
if (Ext.getCmp(record.data.uuid)) {
console.log('THERE IS SUCH UUID');
}
//tabb[0].setActiveTab(gallery_view);
}
},
And the problem is in the last line. When i uncomment tabb[0].setActiveTab(gallery_view) the new tab is focused but empty and if i leave the line commented the new tab with dataView is populated with data but not focused. I really dont have any idea why setActiveTab() causes DataView not to display at all. The gallery_view widget is Ext.view.View extension.
I'm not sure how come you get the data view if there's no setActiveTab, but there seem to be some issue with this code:
var gallery_view = Ext.widget('gallery_view');
var ImageStore = Ext.create('Gallery.store.Images');
ImageStore.load({url: 'myphoto/index.php/api/feed/json/' + record.data.uuid});
Ext.apply(gallery_view, {
title: record.data.name,
id: record.data.uuid,
closable:true,
store: ImageStore
});
First you create a new widget with Ext.widget() and then you override some config options with Ext.apply(). To my understanding, the latter is fine for primitives but not for objects/arrays.
Generally speaking, the configs are there for the purpose of telling the constructor how to initialise a specific instance of the class. A change to an object's title through Ext.apply() could work if the object is not rendered yet, but not a change to a store config (upon construction the component might start listening to various store events, this won't happen by a simple Ext.apply() which only copies configs from one object to another - you've already missed the train for a component that was created as far as listening to store events goes).
Please try this instead:
var ImageStore = Ext.create('Gallery.store.Images');
ImageStore.load({url: 'myphoto/index.php/api/feed/json/' + record.data.uuid});
var gallery_view = Ext.widget('gallery_view', {
title: record.data.name,
id: record.data.uuid,
closable:true,
store: ImageStore
});