SAP UI5 XML View Tiles Icon not working - tiles

I have a XML View:
<mvc:View height="100%" xmlns:core="sap.ui.core" xmlns:mvc="sap.ui.core.mvc"
xmlns="sap.m" controllerName="my.own.controller">
<App>
<Page showHeader="false" enableScrolling="false">
<TileContainer id="container" tileDelete="handleTileDelete" tiles="{/TileCollection}">
<StandardTile icon="sap-icon://{icon}" number="{number}" title="{title}" info="{info}" infoState="Success" />
</TileContainer>
<footer>
</footer>
</Page>
</App>
And I have a js:
function initialLoad(){
// create some dummy JSON data
var data = {
"TileCollection" : [{
"icon":"history",
"number":"3",
"title" : "Project History",
"info": "click to view",
"infoState" : "Success"
}]
};
// instantiate the View
sap.ui.localResources("XMLViews");
var app = new sap.m.App({initialPage:"welcome"});
var myView = sap.ui.xmlview({id:"welcome", viewName:"XMLViews/welcome"});
app.addPage(myView);
// create a Model and assign it to the View
var oModel = new sap.ui.model.json.JSONModel();
oModel.setData(data);
myView.setModel(oModel);
// put the View onto the screen
myView.placeAt("content");}
The problem is the icon is not showing up. If I hard code in my XML view:
icon="sap-icon://history"
Then the icon is showing up correctly.
I am stuck with this problem for one day and I appreciate if you could give me some hint!
Thanks!

The Way of binding data to the icon property is incorrect. it should be in this way.
icon="{icon}"
Instead make the change in your json as below:
var data = {
"TileCollection" : [{
"icon":"sap-icon://history",
"number":"3",
"title" : "Project History",
"info": "click to view",
"infoState" : "Success"
}]
};
I think this will work.

Related

Datepicker control is not displayed correctly inside of kendo ui template

I have a kendo ui template with a datepicker control
<script type="text/x-kendo-template" id="tmplStep1">
<form>
Date: <input id="datepicker" maxlength="10"/>
<i>(mm/dd/yyyy)</i><br />
</form>
</script>
I'm using a Windows Popup to display the template in this way
var detailsTemplate = kendo.template($("#tmplStep1").html());
dataItem = this.dataItem(e);
var wnd = $("#winDate")
.kendoWindow({
title: "Form",
modal: true,
visible: false,
resizable: false,
width: 100,
appendTo: "form#frm"
}).data("kendoWindow");
wnd.content(detailsTemplate(dataItem));
wnd.center().open();
I know, I need to initialize the datepicker, but I don't know how to do it. I put the below instruction outside of the template, but obviously it is not working, the control displayed is a simple textbox.
<script>
$("#datepicker").kendoDatePicker();
</script>
Does anyone know how to resolve it?
call $("#datepicker").kendoDatePicker(); right after you set template as window content, because before that temlate is not a part of DOM yet:
...
wnd.content(detailsTemplate(dataItem));
$("#datepicker").kendoDatePicker();
wnd.center().open();

Unable to access model from core in sapUI5

Follow up to related question
here
For whatever reason I'm unable to access my model in my xml view when it's set through sap.ui.getCore().setModel(). If I set it on the this.getView() I have no problems at all.
My view XML
<mvc:View controllerName="ca.toronto.rcsmls.webapp.controller.Login"
xmlns="sap.m" xmlns:mvc="sap.ui.core.mvc" xmlns:l="sap.ui.layout">
<Page title="{i18n>loginPageTitle}">
<content>
<Panel id="loginPanel" busyIndicatorDelay="0"
headerText="{i18n>loginPanelTitle}" class="sapUiResponsiveMargin loginPanel"
width="auto">
<l:VerticalLayout width="100%">
<Input type="Text" placeholder="{i18n>loginUidHolder}" value="{/mlsUser/uid}" />
<Input type="Password" placeholder="{app>/Password}"
value="{/mlsUser/password}" />
<Button text="{i18n>loginButtonText}" press="doLogin"
class="sapUiSmallMarginEnd customBold" width="100%" />
</l:VerticalLayout>
</Panel>
</content>
</Page></mvc:View>
My controller JS contains this for setModel()
onInit : function() {
sap.ui.getCore().setModel(new sap.ui.model.json.JSONModel("webapp/controller/app.json"), "app");
}
Again, if I set the model to this.getView().setModel() instead of getCore() XML and controller work fine together. I also added data-sap-ui-xx-bindingSyntax="complex" to my index.html but that didn't seem to make a difference. Any help would be appreciated.
Edited to include more information
My Component.js
sap.ui.define([
"sap/ui/core/UIComponent",
"sap/ui/model/json/JSONModel",
], function (UIComponent, JSONModel) {
"use strict";
return UIComponent.extend("ca.toronto.rcsmls.webapp.Component", {
metadata : {
manifest: "json"
},
init : function () {
// call the init function of the parent
UIComponent.prototype.init.apply(this, arguments);
// set data model
var oData = {
mlsUser : {
uid : "",
password : "",
}
};
var oModel = new JSONModel(oData);
this.setModel(oModel);
// create the views based on the url/hash
this.getRouter().initialize();
}
});
});
My manifest.json
{
"_version": "1.1.0",
"sap.app":
{
"_version": "1.1.0",
"id": "ca.toronto.rcsmls",
"type": "application",
"i18n": "i18n/i18n.properties",
"title": "{{appTitle}}",
"description": "{{appDescription}}",
"applicationVersion":
{
"version": "1.0.0"
},
"ach": "CA-UI5-DOC"
},
"sap.ui":
{
"_version": "1.1.0",
"technology": "UI5",
"deviceTypes":
{
"desktop": true,
"tablet": true,
"phone": true
},
"supportedThemes":
[
"sap_bluecrystal"
]
},
"sap.ui5":
{
"_version": "1.1.0",
"rootView": "ca.toronto.rcsmls.webapp.view.App",
"dependencies":
{
"minUI5Version": "1.30",
"libs":
{
"sap.m":
{
}
}
},
"config":
{
"authenticationService": "http://172.21.226.138:9080/RcsMlsSvc/jaxrs/user/authenticate/",
"assignedWorkService": "http://172.21.226.138:9080/RcsMlsSvc/jaxrs/mls/searchAssignedWork"
},
"models":
{
"i18n":
{
"type": "sap.ui.model.resource.ResourceModel",
"settings":
{
"bundleName": "ca.toronto.rcsmls.webapp.i18n.i18n"
}
}
},
"routing":
{
"config":
{
"routerClass": "sap.m.routing.Router",
"viewType": "XML",
"viewPath": "ca.toronto.rcsmls.webapp.view",
"controlId": "root",
"controlAggregation": "pages"
},
"routes":
[
{
"pattern": "",
"name": "login",
"target": "login"
},
{
"pattern": "work",
"name": "work",
"target": "work"
}
],
"targets": {
"login": {
"viewName": "Login"
},
"work": {
"viewName": "Work"
}
}
},
"resources":
{
"css":
[
{
"uri": "css/style.css"
}
]
}
}
}
Model app.json
{
"BaseURL": "https://smp-pNNNNNNtrial.hanatrial.ondemand.com",
"ES1Root": "https://sapes1.sapdevcenter.com",
"AppName": "qmacro.myfirst",
"Username": "yourusername",
"Password": "yourpassword"
}
I found an example where core binding works here. It is a much simpler application. I'm still trying to figure out the what the differences are between this project and mine
I was made aware of this question by a similar question on Github
By default, UI5 components don't inherit models and binding contexts from their environment (the ComponentContainer where they are placed). This was done for the sake of isolation.
You can change that default behavior by setting the property propagateModel:true for the container:
new sap.ui.core.ComponentContainer({
name: "ca.toronto.rcsmls.webapp.Component",
propagateModel: true
}).placeAt("content");
Documentation for propagateModel can be found in the API reference as well as in the UI5 developer guide (the corresponding paragraph in the latter page was only added recently, it was not available when you raised your question).
But when the model is created in the scope of the component and shall be used inside the component, then there should be no need to add it to the Core. Just assign it to the component to share it between views inside that component:
Assign it either from some method in a view controller
onInit : function() {
this.getOwnerComponent().setModel(
new sap.ui.model.json.JSONModel(
"webapp/controller/app.json"), "app");
}
or during init of the Component.js itself
init : function() {
// create and set model to make it available to all views
this.setModel(
new sap.ui.model.json.JSONModel(
"webapp/controller/app.json"), "app");
// never forget to call init of the base class
UIComponent.init.apply(this, arguments);
}
The most modern approach is to configure the model in the manifest.json and to let the framework instantiate an assign it. See Walkthrough Tutorial - Step 10: Descriptor for Applications for an example.
Using any of these approaches, there should not even be a need to read and set the model in another view, as long as that view is a descendant of the component (part of the control tree returned by createContent).
I experienced the same behavior.
If I create a simple one-file application, without any complex UI elements, the core-based binding works like a charm.
If I create a complex container, like an App with a shell, this kind of binding will not work anymore. It seems that these containers hide the global model from the view.
As a workaround I used the following code snippet:
this.getView().setModel(sap.ui.getCore().getModel(modelName), "modelName");
Or even you can bind the model directly to the control where you want to use.
None of them are the best solution if you have to use the global model in several view/control, but that's working for me.
I the view above only the placeholder of the password field is using your app model. If this placeholder is not filled correctly then I guess the json file could not be loaded or the content is not matching the binding path you use in your view for the placeholder property of the password field. To find out more please post also the content of your json file. It should look somehow like this:
{ "Password" : "Enter your password", ... }
So according to the binding in the view there must be "Password" property at the root level of the data object.
Below you find a running example that should help you. As you can see you it work like a charm, so you can easily put a named model onto the Core and reference it in your view.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SAPUI5 single file template | nabisoft</title>
<script src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-theme="sap_bluecrystal"
data-sap-ui-libs="sap.m"
data-sap-ui-bindingSyntax="complex"
data-sap-ui-compatVersion="edge"
data-sap-ui-preload="async"></script>
<!-- use "sync" or change the code below if you have issues -->
<!-- XMLView -->
<script id="myXmlView" type="ui5/xmlview">
<mvc:View
controllerName="MyController"
xmlns="sap.m"
xmlns:core="sap.ui.core"
xmlns:l="sap.ui.layout"
xmlns:mvc="sap.ui.core.mvc">
<App>
<Page title="My Page Title">
<content>
<Panel id="loginPanel" busyIndicatorDelay="0"
headerText="My Login Panel Title" class="sapUiResponsiveMargin loginPanel"
width="auto">
<l:VerticalLayout width="100%">
<Input type="Text" placeholder="{Enter User ID}" value="{/mlsUser/uid}" />
<Input type="Password" placeholder="{app>/Password}" value="{/mlsUser/password}" />
<Button text="{Login}" press="doLogin" class="sapUiSmallMarginEnd customBold" width="100%" />
</l:VerticalLayout>
</Panel>
</content>
</Page>
</App>
</mvc:View>
</script>
<script>
sap.ui.getCore().attachInit(function () {
"use strict";
//### Controller ###
sap.ui.controller("MyController", {
onInit : function () {
var oData, oModel;
// 1. app model is only used for the placeholder field in the view
oData = {
Password : "Enter your password"
};
oModel = new sap.ui.model.json.JSONModel(oData);
sap.ui.getCore().setModel(oModel, "app");
// 2. default model is used in the view as well
oData = {
mlsUser : {},
Login : "Login now"
};
oModel = new sap.ui.model.json.JSONModel(oData);
sap.ui.getCore().setModel(oModel);
// 3. we need this because of the relative binding
// of the text property of the login button
this.getView().bindElement("/");
}
});
//### THE APP: place the XMLView somewhere into DOM ###
sap.ui.xmlview({
viewContent : jQuery("#myXmlView").html()
}).placeAt("content");
});
</script>
</head>
<body class="sapUiBody">
<div id="content"></div>
</body>
</html>
In this thread some people have mentioned that "sap.ui.getCore() works with small stuff, but for whatever reason not in more complex applications".
#Marc has also posted the right link to the API docs, where you can find the following:
A ManagedObject inherits models from the Core only when it is a
descendant of an UIArea
Of course, you have to know what this means in order write code that does what you expect. Here is a little example that tells you what could happen in case you have a small "misunderstanding" (see below).
The code below creates two instances of sap.m.Text and binds their text properties to a JSONModel, which is available as a named model "core" directly on the Core (retrieved with sap.ui.getCore()). There are 2 buttons, one for each sap.m.Text instance. In the corresponding press handlers of the buttons I just display the text property of the corresponding sap.m.Text instance. As you can see, both sap.m.Text instances are bound to the same property in the JSONModel. However, only the second sap.m.Text is added to the DOM.
Now the interesting part, which might be related to the confusion of this thread:
Only the text property of the second sap.m.Text control contains the expected text "Hello World" from the JSONModel. The text property of the first sap.m.Text control does not have the value "Hello World" from the model! This is expected behavior of SAPUI5 and it is documented! So I guess in case you face similar issues in your own "complex" app, then it might be quite probable that you have a hard to find bug related to this "expected" behavior.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SAPUI5 single file template | nabisoft</title>
<script src="https://openui5.hana.ondemand.com/resources/sap-ui-core.js"
id="sap-ui-bootstrap"
data-sap-ui-theme="sap_bluecrystal"
data-sap-ui-libs="sap.m"
data-sap-ui-bindingSyntax="complex"
data-sap-ui-compatVersion="edge"
data-sap-ui-preload="async"></script>
<!-- use "sync" or change the code below if you have issues -->
<script>
sap.ui.getCore().attachInit(function () {
sap.ui.define([
"sap/m/Text",
"sap/m/Button",
"sap/ui/model/json/JSONModel"
], function (Text, Button, JSONModel) {
"use strict";
var oModel = new JSONModel({
hello : "Hello World"
});
sap.ui.getCore().setModel(oModel, "core");
// not in DOM
var oText1 = new Text({
text : "{core>/hello}"
});
//oText1.placeAt("text1"); // uncomment this to enable the binding
// add to DOM
var oText2 = new Text({
text : "{core>/hello}"
});
oText2.placeAt("text2");
// action buttons to display text property of text controls
new Button({
text : "show oText1",
press : function(){
alert("oText1.getText() = " + oText1.getText());
}
}).placeAt("btn1");
new Button({
text : "show oText2",
press : function(){
alert("oText2.getText() = " + oText2.getText());
}
}).placeAt("btn2");
});
});
</script>
</head>
<body class="sapUiBody">
<div id="text1"></div>
<div id="text2"></div>
<span id="btn1"></span>
<span id="btn2"></span>
</body>
</html>
sap.ui.getCore() and this.getView() return not the same object i think it's obvious why this doesn't work.
You are trying to get a object(model) from another object (the core) although the desired model is bound to another object(the view)
it's like i have two colored boxes (one red, one blue) and im trying to get the color red from the blue colored box
Here is an similar issue but the cause in this one depends on the id handling of the views in the UI5 framework:
https://scn.sap.com/thread/3551589
You can see the core and the view does not return the same object.
Also checkout the data binding section on the openui5 website: https://openui5beta.hana.ondemand.com/#docs/guide/e5310932a71f42daa41f3a6143efca9c.html
Create Model in components.js:
var oModel= new sap.ui.model.json.JSONModel;
oModel.loadData("webapp/controller/app.json");
this.setModel(oModel, "app");
Get Model:
This will create a reference to the model which has been created in the Components.js
var oModel= this.getView().getModel("app");
Refer to the model with "{modelName(app)>desiredProperty}"
<Input type="Password" placeholder="{app>Password}"
value="{app>mlsUser/password}" />
could you post your json content?
Hope this was helpful

How to use Ajax to update RenderBody() section with VS 2012 Internet Template?

I've looked at few examples where Ajax can be used to update divs or other elements with ids. I have not been able to find an example that uses Ajax with Razor views to help me with the following.
My page is a standard Menu at the top, body in the middle, and a footer. There is no real need to update the header and footer each time. In fact, my page only requires a section of the Body to be updated based on menu clicks and actionlinks on the page. I'm testing this with the Internet Template that is created using VS 2012 if that helps such that I do not have to clutter this request with a bunch of code snippets. I am using Razor views and C# for coding preferences.
So, given the default _Layout.cshtml file, how would I load the About page i.e. RenderBody() section via Ajax? I've tried adding Ajax.BeginForm(...) to my _Layout.cshtml file around one div with an UpdateTargetId that matches a div that I wrapped around the RenderBody() call, returned a partial view from my controller, but that's not quite right. What I get is my partial view only. (The About page with no menu, footer, etc. just the code on the About page)
Would someone kindly share a link that demonstrates this functionality or kindly share the code that does what I desire i.e. swap index view with about view without a full page refresh? Some explanation of what I'm missing would be nice, but I'm sure I could deduce from a solid example where I went awry. As always, your time is much appreciated.
EDIT: Using Jasen's suggestion
_Layout.cshtml
<nav>
<ul id="menu">
<li>#Html.ActionLink("Home", "Index", "Home")</li>
<li>#Ajax.ActionLink("About", "About", "Home", null, new AjaxOptions { HttpMethod = "get", UpdateTargetId = "body" }, new { })</li>
<li>#Html.ActionLink("Contact", "Contact", "Home")</li>
</ul>
</nav>
....
Inside my div id="body"
#RenderSection("featured", required: false)
<section class="content-wrapper main-content clear-fix">
#RenderBody()
</section>
.....
HomeController.cs
public ActionResult About()
{
ViewBag.Message = "Your app description page.";
return PartialView();
}
......
Here is a simple example with jquery. The About partial gets injected into the div with id="body".
<button>About</button>
<div id="body"></div>
$(function () {
$("button").on("click", function(e) {
$.get("Home/About").done(function(result) {
$("#body").html(result);
});
});
));
Controller Action
[HttpGet]
public ActionResult About()
{
return PartialView("About");
}
About.cshtml
#{ Layout = null }
<h2>Home/About</h2>
<p>Blah... </p>
Edit: Maybe a better example is to use a link instead
#Html.ActionLink("About", "About", "Home", null, new { #class="menu-button" })
<div id="body"></div>
$(function () {
$(".menu-button").on("click", function(e) {
e.preventDefault();
var url = $(this).attr("href");
$.get(url).done(function(result) {
$("#body").html(result);
});
});
});
Edit: Without jquery you want to use Ajax.ActionLink() instead of Ajax.BeginForm()
#Ajax.ActionLink("About", "About", "Home", null, new AjaxOptions { HttpMethod = "get", UpdateTargetId = "body" }, new { })
<div id="body"></div>
In your HomeController.cs
public PartialViewResult About()
{
ViewBag.Message = "Your app description page.";
return PartialView();
}
In your _Layout.cshtml do not forget to import:
<script src="~/Content/Scripts/jquery-1.9.1.min.js" type="text/javascript"></script>
<script src="~/Content/Scripts/jquery.unobtrusive-ajax.min.js" type="text/javascript"></script>

Fancybox 2 Title "Inside" on YouTube (iframe)?

Is it possible to put the title "inside" when using Fancybox 2 for YouTube/iFrame content?
Anytime I try to insert
title: {
type: 'inside'
}
the video then plays in a new window at full screen.
Here is what I'm currently using:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min.js"></script>
<link rel="stylesheet" href="lib/jquery.fancybox.css" type="text/css" media="screen" />
<script type="text/javascript" src="lib/jquery.fancybox.pack.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$(".vids").fancybox({
maxWidth : 800,
maxHeight : 600,
fitToView : false,
width : '60%',
height : '60%',
autoSize : false,
closeClick : false,
openEffect : 'none',
closeEffect : 'none'
});
});
</script>
As a bonus, I would like the Title text to contain a link that opens _blank if it's possible.
Also, perhaps related, to make videos play in all browsers, I have to alter the YouTube links, rather than doing something like:
<a class="vids fancybox.iframe" href="http://www.youtube.com/watch?v=whatever">
I have to change it, and insert the word "embed", such as:
<a class="vids fancybox.iframe" href="http://www.youtube.com/embed/whatever">
Is this a proper method?
Thanks in advance.
Many question eh?
First, to get the title inside the fancybox use the option helpers like
helpers: { title : { type : 'inside' } }
Second, to set a title with a link ... I would advice to you to set a data-* attribute in your anchor so the link won't show up in the normal browser's tooltip ... something like
<a class="vids" href="http://www.youtube.com/watch?v=whatever" title="normal title" data-caption="open video
Notice that I didn't add target="_blank" since clicking on the link will navigate automatically to the next page (and closing fancybox)
Then use the callback beforeShow to construct the title
beforeShow: function(){
this.title = this.title + " " + $(this.element).data("caption");
}
Third, the proper way to display youtube videos is having a normal link (like in me second example above) and no more. Then include the fancybox-media js file in your document like
<script type="text/javascript" src="lib/helpers/jquery.fancybox-media.js"></script>
(check your own path)
... and use the helpers option to set the media like
helpers : {media : {} }
so, summarizing, your html should be something like
<a class="vids" href="http://www.youtube.com/watch?v=whatever" title="normal title" data-caption="open video
and your fancybox custom script like
<script type="text/javascript">
$(document).ready(function() {
$(".vids").fancybox({
maxWidth : 800,
maxHeight : 600,
fitToView : false,
width : '60%',
height : '60%',
autoSize : false,
closeClick : false,
openEffect : 'none',
closeEffect : 'none',
helpers : {
title : { type : 'inside' },
media : {}
},
beforeShow: function(){
this.title = this.title + " " + $(this.element).data("caption");
}
});
});
</script>

mvc3 Html.ActionLink as image not as text

<div class="orderby_name">
#Html.ActionLink(" ", "DisplayCategory", "Categories", new { articleSortBy = "Name", articleSortType = "asc" }, null)
</div>
i am lookin in razor if exist ImageLink. Now i have #Html.ActionLink and becouse i do not have any text name i can not click on it. I want to have image as link.
How can i make image as link in razor?
The built-in helper cannot do that.
You need to create an ordinary <a href="#Url.Action(...)"> tag.
Hope this code is helpful
#using (Html.BeginForm())
{
<a href='#Url.Action("Index")'>
<img src='#Url.Content("../../Content/Images/head.jpg")' alt="Home Page">
</a> }
Actually it looks like there is a way.. if you add a CSS rule to the htmlAttributes, as is shown in the top answer of this post:
Html.ActionLink as a button or an image, not a link
In asp.net mvc 3 the code you have works with the single space for the link text, just add a class name that points to an image (the class name below points to a font awesome image):
#Html.ActionLink(" ", "ActionName", "ControllerName",
new {UniqueId = item.UniqueId},
new { #class = "fa fa-download", #title = "Download the document" })
And add some css to prevent the image from having an underline:
a.fa
{
text-decoration:none;
}

Resources