Update grid using NotifyChange - grid

In my code, I have a textbox in which you can insert text and a button to 'publish' that text. Beneath there is a grid, in which all the previously published posts appear. The issue is that, using the #NotifyChange doesn't work, or I dont know how it works well enough to make it update the grid. Here is the .zul:
<!--Skipping code-->
<center style="padding:15px;" border="none">
<window>
<window title="Make post" border="normal">
<textbox id="publish" placeholder="Make a post"
height="40px" width="67%" multiline="true">
<attribute name="onChanging">
<![CDATA[
String value = event.value;
publSize.setValue("" + value.length() + "/300");
]]>
</attribute>
</textbox>
<space width="1%"/>
<textbox id="publSize" height="40px" width="6%" style="text-align:center" disabled="true" placeholder="0/300"/>
<space width="1%"/>
<button id="publicaBttn" label="Publicar" height="40px" width="25%" onClick="#command('addNewPost', p=publish)"/>
</window>
<separator bar="false"/>
<grid id="postGrid" height="550px" model="#init(vm.posts)" emptyMessage="Nothing in Posts.">
<template name="model">
<row>
<window border="normal">
<caption id="userName" label="#load(each.username)"/>
<textbox id="infoPost" readonly="true" value="#load(each.info)" multiline="true" rows="4" width="100%" mold="rounded"/>
<separator bar="true"/>
<hlayout>
<div>
<button label="Like" onClick="#command('addLike', index=each.index)"/>
</div>
<div hflex="true">
<textbox id="likeTB" disabled="true" width="3%" style="text-align:center" value="#load(each.likes)"/>
</div>
<div style="padding-right">
</div>
</hlayout>
</window>
</row></template></grid></window></center><!--...--></borderlayout></zk>
Here is the java controller:
#Command("addNewPost")
#NotifyChange("hConn")
public void addPost(#BindingParam("p") Textbox tbx) {
String text = tbx.getValue();
if (text == "") {
Messagebox.show("There must be text in a post.", null, 0, Messagebox.ERROR);
}
if (text.length() > 300) {
Messagebox.show("Posts must be under 300 characters.", null, 0, Messagebox.ERROR);
} else {
hConn.addPost(usuario,text);
}
BindUtils.postNotifyChange(null,null,this,"postGrid");
tbx.setValue("");
}
#Command("addLike")
#NotifyChange("hConn")
public void addLike(#BindingParam("index") String index) {
hConn.addLike(Integer.parseInt(index));
BindUtils.postNotifyChange(null,null,this,"postGrid");
}
When I either add a like or make i new post, the grid doesnt update to show the new like or the new post added. How can i solve this?

#init method is called when the view model is initialised. If you want updates you need to change model="#init(vm.posts)" to model="#load(vm.posts)". (I assume getPosts() in your view model returns hConn.
Some other observations:
You could use a custom constraint for your textbox. Something like (untested):
<textbox placeholder="Make a post" height="40px" width="67%" multiline="true" constraint="#load(vm.max300Constraint)" />
and in your view model:
public Constraint getMax300Constraint() {
return new Constaint() {
public void validate(Component comp, Object value) throws WrongValueException {
// check if text is greater than 300 characters
}
}
}
Another option is as follows:
<textbox placeholder="Make a post" height="40px" width="67%" multiline="true" onChanging="#command('checkLength', text=event.value)" />
and in your view model:
#Command
public void checkLength(#BindingParam("text") String text) {
// check text length
}
Both of these options also mean you can avoid putting the textbox component in your view model thereby embracing the values of MVVM.

Related

How to achieve same like Segemented button with toggle button(sugg) ,change to next onclicked

As learnt from previous question of mine(how to change segmented button to next on clicked) , I used a Segmented button to do so as:
My expected results were:
when Next is pressed INDICATOR2 should be active and on second press INDICATOR3 should be active.
when on INDICATOR2 if Previous is pressed both INDICATOR2 and INDICATOR1(which is current one) should be active.
As I am using segmented button here, the 2) can't be achieved ,and also was suggested using a toggle button would do instead a segmented button.
so I tried as,
<HBox id="toggleButton1">
<ToggleButton text="BUTTON1" enabled="true" pressed="true" press="onPress">
</ToggleButton>
<ToggleButton text="BUTTON2" enabled="true" pressed="false" press="onPress">
</ToggleButton>
<ToggleButton text="BUTTON3" enabled="true" pressed="false" press="onPress">
</ToggleButton>
</HBox>
<Button text="Previous" press="onPressPrevious" enabled="true"> </Button>
<Button text="Next" press="onPressNext" enabled="true"> </Button>
For this ,
How can I write JS code such that :
when Next is pressed BUTTON2 should be active and on second press BUTTON3 should be active.
when on BUTTON2 if Previous is pressed both BUTTON2 and BUTTON1(which is current one) should be active.
How can I set these Toggle Buttons width set to whole page(tried my luck display: block; width=100% in CSS but couldn't work)
I have no knowledge on JS at least to give a try , any help so that I would go through it and learn so, TIA
Here is a sample of using the three ToggleButtons as one SegmentedButton. I am caching the list of buttons in a local variable, since there is only one group of buttons. You could adapt it to support multiple such groups if needed, by either adding more local variables, or by getting the relevant list of buttons each time.
If next is pressed, it jumps to the next button. If previous is pressed, it enables all previous buttons. If a toggle button is pressed, it disables all others, much like a SegmentedButton.
As for the size, you need to set a few flexbox related properties. fitContainer on the HBox so it stretches 100% and growFactor=1 on the toggle buttons so they actually use all that space. Even then, it seems the buttons themselves don't like stretching much, so I set an additional CSS style to force them.
sap.ui.define("myController", [
"sap/ui/core/mvc/Controller"
], function(Controller) {
"use strict";
var toggleButtons1;
return Controller.extend("myController", {
onInit: function() {
toggleButtons1 = this.byId("toggleButtons1").getItems();
},
onPressNext: function(e) {
for (var i = 0; i < toggleButtons1.length - 1; ++i) {
if (toggleButtons1[i].getPressed()) {
toggleButtons1[i].setPressed(false);
toggleButtons1[i + 1].setPressed(true);
break;
}
}
},
onPressPrevious: function() {
for (var i = toggleButtons1.length - 1; i > 0; --i) {
if (toggleButtons1[i].getPressed()) {
toggleButtons1[i - 1].setPressed(true);
}
}
},
onPress: function(e) {
var btn = e.getSource();
if(!btn.getPressed()) {
btn.setPressed(true);
return;
}
for (var i = 0; i < toggleButtons1.length; ++i) {
if (toggleButtons1[i] != btn) {
toggleButtons1[i].setPressed(false);
}
}
},
onPress1: function(e) {
this.onPress(e);
alert("Do something here!");
}
});
});
sap.ui.require(["sap/ui/core/mvc/XMLView"], function(XMLView) {
XMLView.create({
definition: $('#myView').html()
}).then(function(oView) {
oView.placeAt('content');
});
});
.fullWidthButtons button {
width: 100%;
}
<html>
<head>
<meta charset="utf-8">
<script id='sap-ui-bootstrap' src='https://sapui5.hana.ondemand.com/resources/sap-ui-core.js' data-sap-ui-theme='sap_fiori_3' data-sap-ui-libs='sap.m'></script>
<script id="myView" type="sapui5/xmlview">
<mvc:View xmlns:mvc="sap.ui.core.mvc" xmlns="sap.m" controllerName="myController">
<HBox id="toggleButtons1" fitContainer="true" class="fullWidthButtons">
<ToggleButton text="BUTTON1" enabled="true" pressed="true" press=".onPress1">
<layoutData>
<FlexItemData growFactor="1" />
</layoutData>
</ToggleButton>
<ToggleButton text="BUTTON2" enabled="true" pressed="false" press=".onPress">
<layoutData>
<FlexItemData growFactor="1" />
</layoutData>
</ToggleButton>
<ToggleButton text="BUTTON3" enabled="true" pressed="false" press=".onPress">
<layoutData>
<FlexItemData growFactor="1" />
</layoutData>
</ToggleButton>
</HBox>
<Button text="Previous" press="onPressPrevious" enabled="true" />
<Button text="Next" press="onPressNext" enabled="true" />
</mvc:View>
</script>
</head>
<body class='sapUiBody'>
<div id='content'></div>
</body>
</html>

how to have 4 columns in a row simpleform SAPUI5

I need to align columns in <form:SimpleForm>. I need 4 columns in a row but only 2 columns are aligned. Here is my example, Please refer JsBin
Needed output :
label input-field label input-field
current output :
label input-field
label input-field
To use a new container on the right, simply set an empty title.
But be aware tabbing won't be from left to right, top to bottom but (per container) top to bottom, left to right
After all, it just a SimpleForm ;-)
See this working example (please run the example full-page, otherwise it will still show the fields top-town because of the responsive nature):
sap.ui.controller("view1.initial", {
onInit : function() { }
});
sap.ui.xmlview("main", {
viewContent: jQuery("#view1").html()
})
.placeAt("uiArea");
<script id="sap-ui-bootstrap"
src="https://sapui5.hana.ondemand.com/resources/sap-ui-core.js"
data-sap-ui-theme="sap_bluecrystal"
data-sap-ui-xx-bindingSyntax="complex"
data-sap-ui-libs="sap.m"></script>
<div id="uiArea"></div>
<script id="view1" type="ui5/xmlview">
<mvc:View
controllerName="view1.initial"
xmlns="sap.m"
xmlns:l="sap.ui.layout"
xmlns:f="sap.ui.layout.form"
xmlns:core="sap.ui.core"
xmlns:mvc="sap.ui.core.mvc">
<f:SimpleForm
maxContainerCols="2"
editable="true"
layout="ResponsiveGridLayout"
labelSpanL="4"
labelSpanM="4"
emptySpanL="0"
emptySpanM="0"
columnsL="2"
columnsM="2">
<f:content>
<core:Title text="A Title" />
<Label text="1st label" required="true" />
<Input value="Blah" />
<core:Title text="" /> <!-- empty title so it looks like this container belongs to the left one -->
<Label text="2nd label" required="true" />
<Input value="Blah" />
</f:content>
</f:SimpleForm>
</mvc:View>
</script>

Declaring asp.net control inside HTML markup

Is it possible to write something like this?
<input class="form-control" id="name" name="name"
placeholder='<asp:Label runat="server" ID="lblFormName"></asp:Label>' type="text" required autofocus />
Solution 1: let ASP.Net render extra attributes
You can use the native TextBox control :
<asp:TextBox runat="server"
ID="name"
required="required"
autofocus="autofocus"
CssClass="form-control"
placeholder="myplaceholder" />
Extra attributes (ones that are not properties of the TextBox class), will be rendered as is:
Html result:
<input name="ctl00$MainContent$name"
type="text"
id="MainContent_name"
class="form-control"
required="required"
autofocus="autofocus"
placeholder="myplaceholder" />
If the generated id must be explicit, you can add CliendIDMode="Static":
<asp:TextBox runat="server"
ID="name"
required="required"
autofocus="autofocus"
CssClass="form-control"
placeholder="myplaceholder"
ClientIDMode="Static" />
Result:
<input name="ctl00$MainContent$name"
type="text"
id="name"
class="form-control"
required="required"
autofocus="autofocus"
placeholder="myplaceholder" />
Solution 2: write your own control
An even better approach is to extend the textbox class:
using System.Web.UI.WebControls;
namespace WebApplication1.Controls
{
public class TextBoxEx : TextBox
{
protected override void AddAttributesToRender(System.Web.UI.HtmlTextWriter writer)
{
if (AutoFocus) writer.AddAttribute("autofocus", "autofocus");
if (Required) writer.AddAttribute("required", "required");
if (!string.IsNullOrEmpty(PlaceHolder)) writer.AddAttribute("placeholder", PlaceHolder);
base.AddAttributesToRender(writer);
}
public string PlaceHolder
{
get {
var obj = ViewState["PlaceHolder"];
return obj != null ? (string)obj : default(string);
}
set { ViewState["PlaceHolder"] = value; }
}
public bool AutoFocus
{
get {
var obj = ViewState["AutoFocus"];
return obj != null ? (bool)obj : default(bool);
}
set { ViewState["AutoFocus"] = value; }
}
public bool Required
{
get {
var obj = ViewState["Required"];
return obj != null ? (bool)obj : default(bool);
}
set { ViewState["Required"] = value; }
}
}
}
Then you can register and use the control:
<%# Register Assembly="WebApplication1" TagPrefix="local" Namespace="WebApplication1.Controls" %>
....
<local:TextBoxEx runat="server" required="true" autofocus="true" PlaceHolder="my placeholder" />
You want to assign some value to one of HTML element's properties?
<asp:HiddenField runat="server" ID="lblFormName" />
<input class="form-control" id="name" name="name" placeholder='<%# lblFormName.Value %>' ...
Then you pass lblFormName.Value from CodeBehind.
You cannot declare a single ASP.NET control in a pure HTML page. It must be a ASP.NET page (aspx) which is processed by the server.

Password-Box not showing any content

I have a small websolution that needs the user to input a password. I have two input boxes
<input type="password" runat="server" id="m_txtPassword1"/>
If I set some chars to the Value-property of the control like this:
m_txtPassword1.Value="someChars";
The password box is rendered empty. No bullets are shown. If I look into the rendered html-source, also no value-tag has been rendered. If I change the type to
<input type="text" runat="server" id="m_txtPassword1"/>
the chars are shown. Is this by design? How can I disable this feature?
Please note, I don't want to put a real password into the value-property, I only want to show the user that there is already a password set, and this is IMO done best with some 8 bullets in the input-control. But for this, I need the possibility to set the value-property of the control.
Update
For all, having the same problem: I have tried to declare <asp:textbox id="m_txtPassword1" runat="server" TextMode="Password" /> with the same result. Also m_txtPassword1.Attributes["value"]="someChars" has not helped.
It seems that this is realy not possible.
As a workaround, I declared the password-boxes as plain html without the runat="server" and have set the value-property in markup (via two properties from the code-behind). Not nice but I really want to show the user that he has already entered a password.
Another workaround would be to set the value through javascript on load.
This is by default. You cannot set a password.
I make this works,
<html>
<head>
<script type="text/javascript">
function alertValue()
{
alert(document.getElementById("password1").value);
}
function setpassword()
{
password1.value="someChars";
}
</script>
</head>
<body>
<form>
<input type="password" id="password1" value="" />
<input type="button" id="button1" onclick="alertValue()" value="Show default value" />
<input type="button" id="button2" onclick="setpassword()" value="Set value" />
</form>
</body>
</html>
Try this:
http://jsbin.com/ocexo5
It is by design, for security reasons - so that the password is not in the
HTML in plain text.
Now, you could write out javascript to set the value property of the textbox
on the client, of course this would still mean that you have the password in
plain text in the HTML.
Here is example of the page:
Markup:
<script type="text/javascript">
function setPwd()
{
var Pwd = "<%=Pwd %>";
var txtText = document.getElementById("MainContent_txtText");
txtText.value = Pwd;
}
</script>
<input type="password" id="txtText" runat="server"/>
And code-behind:
public partial class _Default : System.Web.UI.Page
{
public string Pwd;
protected void Page_Load(object sender, EventArgs e)
{
Pwd = "password";
ClientScript.RegisterStartupScript( this.GetType(),"somescript","setPwd();",true);
}
}
Textbox11.Attributes.Add("Value",whatever_your_password_is)

Appended content using jQuery 'append' is not submitted?

I'm new to jQuery so this may be a real simple answer. I have a ASP.NET project that I'm trying to dynamically add content to an ASP Label element by typing into a text box and clicking a button. Sounds simple right? Well, I can get the content to added, but when the form is submitted the Label element is still empty? Why is the new data not submitted? What step am I missing? Please help. Here's some sample code:
<asp:Label ID="lblContainer" Text="" runat="server" />
<input type="text" name="tag" id="tag" />
<input type="button" name="AddTag" value="Add" class="button" onclick="addTag();" />
function addTag() {
if ($("#tag").val() != "") {
$("#lblContainer").append('$("#tag").val()' + '<br />');
$("#tag").val("");
}
}
Asp.Net doesn't work that way because it won't send the contents of a <span> tag in the HTTP Post when your form is submitted. You need to add that content to an <input> of some sort. Try something like this instead.
<span id="tagContainer" runat="server"></span>
<input type="text" name="tag" id="tag" />
<input type="button" name="AddTag" value="Add" class="button" onclick="addTag();" />
<!-- Use a hidden field to store the tags -->
<asp:HiddenField id="tagText" runat="server" />
function addTag() {
var newTag = $.trim($("#tag").val());
if (newTag != "") {
$("#tag").val("");
$("#tagContainer").append(" "+ newTag);
// append the newTag to the hidden field
var $tagText = $("#tagText");
$tagText.val($tagText.val() + " " + newTag);
}
}
Then in your asp.net code you can retrieve the value like so..
string myTagText = tagText.value;

Resources