Im trying to create search help using Odata service but my table is showing as undefined in controller, here is my code plz help
index.html
<head>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta charset="UTF-8">
<title>search_help</title>
<script id="sap-ui-bootstrap"
src="../../resources/sap-ui-core.js"
data-sap-ui-libs="sap.m,sap.ui.commons,sap.ui.table,sap.ui.ux3"
data-sap-ui-theme="sap_belize"
data-sap-ui-compatVersion="edge"
data-sap-ui-resourceroots='{"search_help": ""}'>
</script>
<link rel="stylesheet" type="text/css" href="css/style.css">
<script>
sap.ui.getCore().attachInit(function() {
new sap.m.Shell({
app: new sap.ui.core.ComponentContainer({
height : "100%",
name : "search_help"
})
}).placeAt("content");
});
</script>
</head>
<body class="sapUiBody" id="content">
</body>
view1.view.js
sap.ui.jsview("search_help.view.View1", {
getControllerName: function() {
return "search_help.controller.View1";
},
createContent : function(oController) {
var oPanel = new sap.ui.commons.Panel({
text : "Select Order ID"
});
var oLayoutMatrix = new sap.ui.commons.layout.MatrixLayout({
width : "60%",
widths : [ "30%", "40%", "30%" ]
});
var oOrderLabel = new sap.ui.commons.Label("idOrderLabel",
{text: "Order ID"});
// Input Field for Material Number with Value Help
var oOrderInput = new sap.ui.commons.ValueHelpField("idOrderInput", {
valueHelpRequest: function(oEvent){
var oValueHelpDialog = new sap.ui.ux3.ToolPopup({
modal: true,
inverted: false,
title: "Select Order Number",
opener: "idOrderInput",
closed: function (oEvent){
}
});
var oOkButton = new sap.ui.commons.Button({
text: "OK",
press: function (oEvent) {
oEvent.getSource().getParent().close();
}
});
var oHelpTable = new sap.ui.table.Table("pTab1",{
selectionMode: sap.ui.table.SelectionMode.Single,
visibleRowCount: 7,
width: "300pt"
});
oHelpTable.addColumn(
new sap.ui.table.Column({
label: new sap.ui.commons.Label({text: "Maintenance Plane"}),
template: new sap.ui.commons.TextField().bindProperty("value", "Planplant"),
sortProperty: "Planplant",
filterProperty: "Planplant"
})
);
oHelpTable.addColumn(
new sap.ui.table.Column({
label: new sap.ui.commons.Label({text: "Order Number"}),
template: new sap.ui.commons.TextField().bindProperty("value", "Orderid"),
sortProperty: "Orderid",
filterProperty: "Orderid"
})
);
oHelpTable.addColumn(
new sap.ui.table.Column({
label: new sap.ui.commons.Label({text: "OrderType"}),
template: new sap.ui.commons.TextField().bindProperty("value", "OrderType"),
sortProperty: "OrderType",
filterProperty: "OrderType"
})
);
oValueHelpDialog.addContent(oHelpTable);
oValueHelpDialog.addButton(oOkButton);
oValueHelpDialog.open();
}
});
oLayoutMatrix.createRow(oOrderLabel, oOrderInput);
oPanel.addContent(oLayoutMatrix);
return oPanel;
}
});
view1.controller.js
here otable is showing as undefined
sap.ui.define([
"sap/ui/core/mvc/Controller"], function(Controller) {
"use strict";
return Controller.extend("search_help.controller.View1", {
onInit: function()
{
var oModel = new sap.ui.model.odata.ODataModel("/Gateway_Order/sap/opu/odata/SAP/ZP01_FIORI_SRV_01/");
var oTable = this.byId("pTab1");
oTable.setModel(oModel);
oTable.bindRows("/OrderDataSet");
}
});
});
Your problem is how you are fetching the Id of your table.
Solution to your problem is :
var oTable = sap.ui.getCore().byId("pTab1");
However, let us understand the Id creation and fetching.
In JS Views, there are two ways to create Ids.
Way 1: : Provide direct Id. Eg:
var oText = new sap.m.Text('idText'{ text:'Hey!'});
Now, this id -'idText' is associated with your entire application. So, if you have another view, which has a control with same id, you will see duplicate id error in console.
To fetch controls with ids creating with Way1, use the below method:
var oControl = sap.ui.getCore().byId('idText'); // since this is unique everywhere in your application.
Now, let us think 2 or more developers are working in an application and they are creating different views for the application. They may ( with high possibility), create controls with same id. The application will crash when we integrate both views due to duplicate id error. How to solve this?
Way 2: We can use the method createId() of the controller to create a Id for prefixed with view's id. So, this way even if two developers are using the same id, they will end up with different id for controls due to different view Id.
So, let us think we have two views, View1 ( id: view1) and view2 ( id:view2).
If I create a control with same Id in both the controls (using createId() method of controller), two unique id will be generated and duplicate id error will never be raise.
So, View 1( id: view1):
var oText = new sap.m.Text(oController.createId('idText'),{ text:'Hey!'});
Id of oText in view 1 : view1--idText
Similarly,
View 2( id: view2):
var oText = new sap.m.Text(oController.createId('idText'),{ text:'Hey!'});
Id of oText in view 2 : view2--idText
Nicely done. But what if Id of view is auto generated and I might not know what is my view Id? Good question.
Solution is the method : this.byId(). In the cases, where id of controls are prefixed with view's id, always use the method this.byId(). It will append the view's id for you and then search and return the control unique to that view.
So, to fetch oText of View1, you will use (in View1's controller);
var oText = this.byId('idText')// will fetch view1--idText
Again to fetch oText of View2, you will use (in View2's controller);
var oText = this.byId('idText')// will fetch view2--idText
IN XML Views, Id of controls are always prefixed with view's id by framework automatically. This is similar to our Way 2 of JS. ( Way 1 of JS is never possible in XML Views).
View code:
<Text id='idText' text='hey! /> <!-- Id generated is: 'viewid--idText' -->
Hence, when you use XML views, fetching of ID is always done by:
var oControl = this.byId('idText');
I got the output list from odata service to the valuehelprequest table but not able to filter the data.
sap.ui.define([
"sap/ui/core/mvc/Controller
], function(Controller) {
"use strict";
return Controller.extend("Xml_Search.controller.View1", {
handlef4: function(){
var oInput= this.getView().byId("Orderid");
if(!this._oValueHelpDialog){
this._oValueHelpDialog= new sap.ui.comp.valuehelpdialog.ValueHelpDialog("idValueHelp",{
// supportRanges: true,
key: "Orderid",
descriptionKey: "OrderType",
ok: function(oEvent){
var aTokens= oEvent.getParameter("tokens");
oInput.setTokens(aTokens);
this.close();
},
cancel: function(){
this.close();
}
});
}
var oColModel = new sap.ui.model.json.JSONModel();
oColModel.setData({
cols: [
{label: "Orderid", template: "Orderid"},
{label: "OrderType", template: "OrderType"},
{label: "Planplant", template: "Planplant"}
]
});
var oTable = this._oValueHelpDialog.getTable();
oTable.setModel(oColModel,"columns");
var oModel = new sap.ui.model.odata.ODataModel("/Gateway_Order/sap/opu/odata/SAP/ZP01_FIORI_SRV_01/");
oTable.setModel(oModel);
oTable.bindRows({path: "/OrderDataSet", filters: [new
sap.ui.model.Filter("Orderid",sap.ui.model.FilterOperator.EQ,null, oInput)]}
);
this._oValueHelpDialog.open();
}
});
});
Related
I have table sap.ui.table.Table ans I have a model in which some records have links and some doesn't. I want to render the link in the sap.m.Link component in the column and when the link is not available in the record, it should render "Link is not provided." in the sap.m.Text in the column.
As the sap.ui.table.Column has the template aggregation which does not support binding aggregation as it is only 0 or 1 controls supported. And the formatter is also applicable here. Is there any way that the content of the column can be changed runtime according to the module data?
My module data is :
var data = [{
id : 1,
link : 'abc.com'
},
{
id : 2
},
{
id : 3,
link : 'pqr.com'
}]
I am providing the code:
var link = new sap.m.Link({text : "{link}"});
var noLink = new sap.m.Text({text : "Link is not provided."});
var idColumn = new sap.ui.table.Column({
label : [new sap.m.Label({text : "ID"})],
template : [new sap.m.Text({text : "{id}"})]
});
var linkColumn = new sap.ui.table.Column({
label : [new sap.m.Label({text : "Link"})],
template : [??????]
});
var table = new sap.ui.table.Table({
columns : [idColumn, linkColumn]
});
var model = new sap.ui.model.json.JSONModel();
model.setData({items : data});
table.setModel(model);
table.bindRows("/items");
I want to add the link and noLink in the column likColumn runtime according to the data in the module. How can I achieve this?
The display content of each column can be changed using formatter
e.g:
new sap.m.Link({
width: "20em",
//editable: false,
//text: "{items>link}"
text: {
path: "items>link",
formatter: function(link){
if (link === undefined) return "Link is not provided"
return link;
}
}
});
...
oTable.addEventDelegate({
onAfterRendering: function(){
$('#idTable a:contains("Link is not provided")').removeClass("sapMLnk");
}
}, oTable);
UPDATE: This is a jsbin with the full example of what you need:
UPDATED example
I have a parent view which contains a Backgrid view. In the parent view's initialize section I define a variable isWellSelected. The variable is toggled in the Backgrid column logic when a tickbox is checked. I am able to watch the variable toggled when a box is ticked and unticked.
However, once an event fires the variable is no longer in scope for the event to see. I suspect I may need to pass the variable to the Backrgrid view but I am unsure how to do that correctly. Please advise.
app.wellCollectionView = Backbone.View.extend({
template: _.template($('#wellTemplate').html()),
initialize: function() {
this.isWellSelected = false;
// isWellSelected toggled to true when a tickbox is checked in the columns block.
var columns = [...];
// instantiate collection
var wellCollection = new app.wellCollection;
// Set up a grid view to use the pageable collection
var wellGrid = new Backgrid.Grid({
columns: columns,
collection: wellCollection
});
// Initialize the paginator
var paginator = new Backgrid.Extension.Paginator({
collection: wellCollection
});
// Render the template
this.$el.html(this.template());
// Render the grid
this.$el.append(wellGrid.render().el);
this.$el.append(paginator.render().$el);
wellCollection.fetch({reset: true}).then(function () {...});
},
events: {
'click #EvaluateWell': function(){
this.evalWell(event, this.isWellSelected);
console.log("In events - isWellSelected: " + this.isWellSelected);}
},
// More stuff
}
Constructive feedback welcome.
Thanks!
Adding a snippet for "columns" as per JT's request:
var columns = [
{
name: '',
label: 'Select',
cell: Backgrid.BooleanCell.extend({
events : {
'change': function(ev){
var $checkbox = $(ev.target);
var $checkboxes = $('.backgrid input[type=checkbox]');
if($checkbox.is(':checked')) {
$checkboxes.attr("disabled", true);
this.isWellSelected = true;
// Disable all checkboxes but this one
$checkbox.removeAttr("disabled");
} else {
// Enable all checkboxes again
$checkboxes.removeAttr("disabled");
this.isWellSelected = false;
}
}
}
})
}, {
name: "api",
label: "API",
editable: false, // Display only!
cell: "string"
}, {
name: "company",
label: "Operator",
editable: false, // Display only!
cell: "string"
}];
I have a problem with ExtJS and c# does not show me any data only header, I just want to show the records of my sql table, but I could not, my backend works fine and if it returns the records of my BD, the problem is that it does not they are binding, reason why I believe that my JS file is bad and did not find the error so that the registers are shown.
data that return GetCustomer method
app.js:
Ext.require([
'Ext.grid.*',
'Ext.data.*',
'Ext.panel.*',
'Ext.util.*'
]);
Ext.application({
name: 'Fiddle',
launch: function () {
var myStore = new Ext.data.JsonStore({
// Load data at once
autoLoad: true,
// Override default http proxy settings
proxy: new Ext.data.HttpProxy({
pageParam: false, //to remove param "page"
startParam: false, //to remove param "start"
limitParam: false, //to remove param "limit"
noCache: false, //to remove param "_dc"
// Call web service method using GET syntax
url: 'GetCustomers',
// Ask for Json response
headers: {
'Content-type': 'application/json'
}
}),
// Root variable
root: 'data',
// Record identifier
id: 'EmpleadoId',
//reader:Jreader,
// Fields declaration
fields: ['EmpleadoId', 'NombreEmpleado', 'DirectorId'],
});
var grid = new Ext.grid.GridPanel({
// Set store
store: myStore,
// Columns definition
columns: [{
dataIndex: 'EmpleadoId',
header: 'Empleado Id'
}, {
dataIndex: 'NombreEmpleado',
header: 'Nombre Empleado'
}, {
dataIndex: 'DirectorId',
header: 'Director Id'
}],
// Render grid to dom element with id set to panel
renderTo: 'whitespace',
width: 422,
height: 300
});
}
});
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
<link href="~/Content/charts-all.css" rel="stylesheet" />
<script src="~/Scripts/ext-all.js"></script>
<script src="~/Scripts/app.js"></script>
</head>
<body>
<div id="whitespace"></div>
<div>
</div>
</body>
</html>
Controller:
public JsonResult GetCustomers()
{
List<Empleados> lstPersona = new List<Empleados>();
SqlConnection con = new SqlConnection("Server=PC;Database=TestPersona;Trusted_Connection=yes;");
SqlCommand cmd = new SqlCommand("SELECT EmpleadoId,NombreEmpleado,DirectorId FROM Empleados", con);
cmd.CommandType = CommandType.Text;
con.Open();
SqlDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
Empleados emp = new Empleados();
emp.EmpleadoId = Convert.ToInt16(dr["EmpleadoId"]);
emp.NombreEmpleado = dr["NombreEmpleado"].ToString();
emp.DirectorId = Convert.ToInt16(dr["DirectorId"]);
lstPersona.Add(emp);
}
con.Close();
JsonResult res = Json(new { data = lstPersona }, JsonRequestBehavior.AllowGet);
return res;
}
I wonder if someone can help to find what's wrong in this case. I get "Uncaught ReferenceError: text is not defined" in line 6 app.js:
((__t=( text ))==null?'':_.escape(__t))+
driver.js:
var Marionette = require('backbone.marionette');
var TodoView = require('./views/layout');
var initialData = {
items: [
{assignee: 'Scott', text: 'Write a book about Marionette'},
{assignee: 'Andrew', text: 'Do some coding'}
]
};
var App = new Marionette.Application({
onStart: function(options) {
var todo = new TodoView({
collection: new Backbone.Collection(options.initialData.items),
model: new ToDoModel()
});
todo.render();
todo.triggerMethod('show');
}
});
App.start({initialData: initialData});
views/layout.js
var Backbone = require('backbone');
var Marionette = require('backbone.marionette');
var ToDoModel = require('../models/todo');
var FormView = require('./form');
var ListView = require('./list');
var Layout = Marionette.View.extend({
el: '#app-hook',
template: require('../templates/layout.html'),
regions: {
form: '.form',
list: '.list'
},
collectionEvents: {
add: 'itemAdded'
},
onShow: function() {
var formView = new FormView({model: this.model});
var listView = new ListView({collection: this.collection});
this.showChildView('form', formView);
this.showChildView('list', listView);
},
onChildviewAddTodoItem: function(child) {
this.model.set({
assignee: child.ui.assignee.val(),
text: child.ui.text.val()
}, {validate: true});
var items = this.model.pick('assignee', 'text');
this.collection.add(items);
},
itemAdded: function() {
this.model.set({
assignee: '',
text: ''
});
}
});
module.exports = Layout;
todoitem.html
<%- item.text %> — <%- item.assignee %>
Any can me explain why text is not defined?
check your ToDoModel for a typo, the Backbone Model field should be "defaults" not "default", while parsing for a template Marionette view looks for "defaults" field:
https://marionettejs.com/docs/master/template.html#rendering-a-model
so the ToDoModel code should go like this:
...
var ToDo = Backbone.Model.extend({
defaults: {
assignee: '',
text: ''
},
...
You should take a look at the Marionnette's ItemView documentation which explain how to render a template with custom data.
var my_template_html = '<div><%= args.name %></div>'
var MyView = Marionette.ItemView.extend({
template : function(serialized_model) {
var name = serialized_model.name;
return _.template(my_template_html)({
name : name,
some_custom_attribute : some_custom_key
});
}
});
new MyView().render();
Note that using a template function allows passing custom arguments
into the .template function and allows for more control over how the
.template function is called.
With the code you provided at the moment, I can't help.
Marionette calls 'serializeModel' before passing the context to 'template'. So, if you have a backbone.model like
{
.
.
.
attributes: {
text: 'someText',
asignee: 'someAsignee'
}
.
.
}
your template will receive
{
text: 'someText',
assignee: 'someAsignee'
}
I have worked with handlebars but not underscore exactly. There {{this.text}} and {{this.assignee}} works like a charm in the template. So, try this.text or text in place of item.text, see if that works
Hi i have a collection and two views. On my view1 i'm adding data to my collection and view2 will just render and display any changes about the collection. But i can't get it to work. The problem is originally i'm doing this
return new CartCollection();
But they say its a bad practice so i remove changed it. But when i instantiate cart collection on view1 it would add but it seems view2 doesn't sees the changes and renders nothing.
Any ideas?
here is my cart collection.
define([
'underscore',
'backbone',
'model/cart'
], function(_, Backbone, CartModel) {
var CartCollection = Backbone.Collection.extend({
model : CartModel,
initialize: function(){
}
});
return CartCollection;
});
Here is my itemView ( view1 )
AddToCart:function(ev){
ev.preventDefault();
//get data-id of the current clicked item
var id = $(ev.currentTarget).data("id");
var item = this.collection.getByCid(id);
var isDupe = false;
//Check if CartCollection is empty then add
if( CartCollection.length === 0){
CartCollection.add([{ItemCode:item.get("ItemCode"),ItemDescription:item.get("ItemDescription"),SalesPriceRate:item.get("RetailPrice"),ExtPriceRate:item.get("RetailPrice"),WarehouseCode: "Main",ItemType : "Stock",LineNum:1 }]);
}else{
//if check if the item to be added is already added, if yes then update QuantityOrdered and ExtPriceRate
_.each(CartCollection.models,function(cart){
if(item.get("ItemCode") === cart.get("ItemCode")){
isDupe = true;
var updateQty = parseInt(cart.get("QuantityOrdered"))+1;
var extPrice = parseFloat(cart.get("SalesPriceRate") * updateQty).toFixed(2);
cart.set({ QuantityOrdered: updateQty });
cart.set({ ExtPriceRate: extPrice });
}
});
//if item to be added has no duplicates add new item
if( isDupe == false){
var cartCollection = CartCollection.at(CartCollection.length - 1);
var lineNum = parseInt( cartCollection.get("LineNum") ) + 1;
CartCollection.add([{ItemCode:item.get("ItemCode"),ItemDescription:item.get("ItemDescription"),SalesPriceRate:item.get("RetailPrice"),ExtPriceRate:item.get("RetailPrice"),WarehouseCode: "Main",ItemType : "Stock",LineNum:lineNum}]);
}
}
CartListView.render();
}
My cartview (view2)
render: function(){
this.$("#cartContainer").html(CartListTemplate);
var CartWrapper = kendobackboneModel(CartModel, {
ItemCode: { type: "string" },
ItemDescription: { type: "string" },
RetailPrice: { type: "string" },
Qty: { type: "string" },
});
var CartCollectionWrapper = kendobackboneCollection(CartWrapper);
this.$("#grid").kendoGrid({
editable: true,
toolbar: [{ name: "save", text: "Complete" }],
columns: [
{field: "ItemDescription", title: "ItemDescription"},
{field: "QuantityOrdered", title: "Qty",width:80},
{field: "SalesPriceRate", title: "UnitPrice"},
{field: "ExtPriceRate", title: "ExtPrice"}
],
dataSource: {
schema: {model: CartWrapper},
data: new CartCollectionWrapper(CartCollection),
}
});
},
The problem is you've created 2 different instances of CartCollection. So when you update or fetch data into one instance the other does not change but remains the same.
Instead you need to use the same instance of CartCollection across the 2 views (or alternatively keep the 2 insync) .Assuming both views are in the same require.js module you would need to:
1) Instantiate the CartCollection instance and store it somewhere that both views have access to. You could put this in the Router, the parent view, or anywhere else really.
e.g.
var router = Backbone.Router.extend({});
router.carts = new CartCollection();
2) You need need to pass the CartCollection instance to each of your views.
e.g.
var view1 = new ItemView({ collection: router.carts });
var view2 = new CartView({ collection: router.carts });
You may also want to just pass the Cart model to the CartView instead of the entire collection.
e.g.
var cartModel = router.carts.get(1);
var view2 = new CartView({ model: cartModel });