Wednesday, November 17, 2010

uComponent State Fix Bugs


Recently I have to fix this bug to enable the view state after postback.

 

Change the text to use Literal intead of LiteralControl.
Literal will store the view state.

In SelectedItemsTemplate.cs

Change selectedNodeText = new Literal()

var selectedNodeText = new Literal();
selectedNodeText.ID = "SelectedNodeText";
innerDiv.Controls.Add(selectedNodeText);





and when binding change it to grab Literal instead of LiteralControl




void SelectedValues_ItemDataBound(object sender, RepeaterItemEventArgs e)
{
HtmlGenericControl liSelectNode = (HtmlGenericControl)e.Item.FindControl("SelectedNodeListItem");
HtmlAnchor lnkSelectNode = (HtmlAnchor)e.Item.FindControl("SelectedNodeLink");
Literal litSelectNodeName = (Literal)e.Item.FindControl("SelectedNodeText");
HtmlAnchor infoButton = (HtmlAnchor)e.Item.FindControl("InfoButton");





 



OnLoad of MNTP_DataEditor, add this before Binding Selected values




protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);

//add the js/css required
this.AddAllMNTPClientDependencies();

//KK.Fix for postback binding data
if (this.Page.IsPostBack)
{
//if it is postback - we need to bind it from selectedIds
//setting XML Value will give the data source and will trigger proper binding
XmlValue = ConvertToXDocument(SelectedIds);

//When first load this is run on populate form, so it has set the selectedIds.
//but on postback / this value is taken from the client and it must be setup whenever it loads it.
//So I decide to put it here.. when it is postback, we will grab the data from front end and sycn it to the control
//if it is not postback, we setup nothing except before this run, someone set it on populate the form.
}

//bind the repeater if theres a data source
if (SelectedValues.DataSource != null)
{
SelectedValues.DataBind();
}





 



Done…

Tuesday, November 16, 2010

Umbraco Consistency– (Jtree)

 

Today, Finally what happen on my Custom Tree State.
In some reason when in my custom tree, It forget about their state.

And After couple hours, I notice that it’s because I use Pascal Case on my application name. 

In some Umbraco.Tree it store the the state using lowercase whatever appname in database but when i loaded it used whatever the name in database.

Here is the screenshot

shiftApp: function (whichApp, appName) {
89 /// <summary>Changes the application</summary>
90
91 this._debug("shiftApp: " + whichApp + ", " + appName);
92
93 UmbClientMgr.mainTree().saveTreeState(this._currApp == "" ? "content" : this._currApp);
94
95 this._currApp = whichApp.toLowerCase();
96
97 if (this._currApp != 'media' && this._currApp != 'content' && this._currApp != 'member') {
98 jQuery("#buttonCreate").attr("disabled", "true");
99





The reason why I use Pascal Case instead of Camel Case because in .NET  I Store the appAlias and TreeAlias in Enum, So It seems good if I use Pascal Case for consistency.



I guess I need to put it back to Camel Case, otherwise I need to change UmbracoApplicationActions.js for this to work

Wednesday, November 10, 2010

Jgrid with REST Json Webservice

 

Here is the example of integrate your Jgrid with REST webservice.

 

Firstly in your HTML Page. you just need this.

<asp:Content ID="Header" ContentPlaceHolderID="head" runat="server">
<link href="/scripts/js/jQuery/jqGrid/themes/ui.jqgrid.css" rel="stylesheet" type="text/css" />
<link href="/scripts/js/jQuery/jqGrid/themes/redmond/jquery-ui-1.8.2.custom.css"
rel="stylesheet" type="text/css" />
<!-- must have locale before jqGrid-->
<script src="/scripts/js/jQuery/jqGrid/js/i18n/grid.locale-en.js" type="text/javascript"></script>
<script src="/scripts/js/jQuery/jqGrid/js/jquery.jqGrid.min.js" type="text/javascript"></script>

<script type="text/javascript" language="javascript">

//Get Data For JQGrid because we use data Service
function getData(postData) {

//add more parameter
postData.pCatId = '<%=RequestProductCategoryID %>';

//show loading button
$("#load_jqGridTable").show();

//alert(JSON.stringify(postData));

jQuery.ajax({
type: "POST",
url: "/usercontrols/CMS/Webservices/DataService.asmx/LoadJqGridDataProductList" ,

data: JSON.stringify(postData), //we can inject whatever data here
contentType: "application/json; charset=utf-8",
dataType: "json",
//success: function (msg) { alert('success' + msg); },
//use this complete.
complete: function (data, stat) {

//hide
$("#load_jqGridTable").hide();

if (stat == "success") {
var jg = $("#jqGridTable")[0];
//alert('jg : ' + jg);
//note. this example is from a NON-ASP.Net web service.
//there your data is wrapped into dictionary with only one key - '

var t = JSON.parse(data.responseText)['d'];
//alert('t : ' + t);
//alert('t.Name :' + t[0].Name);

//var str = {"page":"1","total":"1","records":"1","rows":[{"id":"1","cell":["True","Product1","1","random"]}]};
//jg.addJSONData(str);

jg.addJSONData(t);
}
else
{
alert('loading data: ' + stat + ' : ' + data.responseText);
}

}
/* this will be handle inside complete
error: function (context) {
alert('error loading data: ' + context.responseText);
}
*/
});
}


jQuery(document).ready(function () {
//jqGrid Defination
jQuery("#jqGridTable").jqGrid({
// the url parameter tells from where to get the data from server
// adding ?nd='+new Date().getTime() prevent IE caching
//url: requestURL,
// datatype parameter defines the format of data returned from the server
// in this case we use a JSON data
//datatype: "json",

//We use JSON Web Service so need to use this
datatype: getData,
// colNames parameter is a array in which we describe the names
// in the columns. This is the text that apper in the head of the grid.
//colNames: ['Publish', 'Name', 'ID', 'Last Modified','ActionLinks'],
colNames: ['Active', 'Name', 'ID', 'Last Modified'],

// colModel array describes the model of the column.
// name is the name of the column,
// index is the name passed to the server to sort data
// note that we can pass here nubers too.
// width is the width of the column
// align is the align of the column (default is left)
// sortable defines if this column can be sorted (default true)
colModel: [
{ name: 'Active', index: 'Active', width: 60, align: "center" },
{ name: 'Name', index: 'Name', width: 470 },
{ name: 'ProductID', index: 'ProductID', width: 95 },
{ name: 'LastModifiedDate', index: 'LastModifiedDate', width: 95 }
//{ name: 'ActionLinks', index: 'ActionLinks', width: 195, sortable: false }
],

// pager parameter define that we want to use a pager bar
// in this case this must be a valid html element.
// note that the pager can have a position where you want
pager: '#jqGridPager',
// rowNum parameter describes how many records we want to
// view in the grid. We use this in example.php to return
// the needed data.
rowNum: 30,
// rowList parameter construct a select box element in the pager
// in wich we can change the number of the visible rows
rowList: [10, 20, 30],
// path to mage location needed for the grid
//imgpath: rootFolder + '/js/jqGrid/themes/bCommerce/images',
//viewrecords defines the view the total records from the query in the pager
//bar. The related tag is: records in xml or json definitions.
viewrecords: true,
caption: "Products",
//height: "100%",
hidegrid: true,
// Set initial grid view.
page: 1,
// sortname sets the initial sorting column. Can be a name or number.
// this parameter is added to the url
sortname: 'Name',
//sets the sorting order. Default is asc. This parameter is added to the url
sortorder: 'asc',
// Events.
gridComplete: function () {
//alert('grid complete');

// Show items not found message.
if (jQuery("#jqGridTable").getGridParam("records") == "0")
jQuery("#jqGridEmptyRecordSet").css('display', 'block');
else
jQuery("#jqGridEmptyRecordSet").css('display', 'none');

// Set width of empty record set to grid width.
jQuery("#jqGridEmptyRecordSet").css('width', jQuery("#jqGridTable").css('width'));
},

});


jQuery("#jqGridTable").jqGrid('navGrid', '#jqGridPager', { edit: false, add: false, del: false });

});
/*
jQuery("#list").jqGrid(
{
url: 'server.php?q=2',
datatype: "json",
colNames: ['Active', 'ProductID', 'Product Name', 'Last Modified', 'Edit ', 'View'],
colModel: [
{ name: 'id', index: 'id', width: 55 },
{ name: 'invdate', index: 'invdate', width: 90 },
{ name: 'name', index: 'name asc, invdate', width: 100 }, { name: 'amount', index: 'amount', width: 80, align: "right" },
{ name: 'tax', index: 'tax', width: 80, align: "right" }, { name: 'total', index: 'total', width: 80, align: "right" }, { name: 'note', index: 'note', width: 150, sortable: false}],

rowNum: 10, rowList: [10, 20, 30],
pager: '#pager',
sortname: 'id', viewrecords: true, sortorder: "desc", caption: "JSON Example" });

jQuery("#list2").jqGrid('navGrid', '#pager2', { edit: false, add: false, del: false });

*/

</script>
</asp:Content>
<asp:Content ID="Content" ContentPlaceHolderID="body" runat="server">
<umb:UmbracoPanel ID="Panel1" runat="server" hasMenu="false" Text="">

<table id="jqGridTable"></table>
<div id="jqGridEmptyRecordSet">No items found.</div>
<div id="jqGridPager"></div>

</umb:UmbracoPanel>


</asp:Content>





 



Finally Create your REST JSON Web Service





/// <summary>
/// Don't change this name attribute, coz this naming is related to jqGrid Spec
/// </summary>
public class JqGridRow
{
public string id { get; set; }
public List<object> cell { get; set; }

public JqGridRow(string id, List<object> cells)
{
this.id = id;
this.cell = cells;
}
}

/// <summary>
/// Don't change this name attribute, coz this naming is related to jqGrid Spec
/// </summary>
public class JqGridData
{
public int page { get; set; }
public int total { get; set; }
public int records { get; set; }
public List<JqGridRow> rows { get; set; }

public JqGridData(int pageNum, int totalPage, int totalRecords, List<JqGridRow> rows)
{

this.page = pageNum;
this.total = totalPage;
this.records = totalRecords;
this.rows = rows;

}
}


/// <summary>
/// Summary description for DataService
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
// To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line.
[ScriptService]
public class DataService : System.Web.Services.WebService
{
/// <summary>
/// This method for mapping the parameter from json, You can't change this because it will make an error in loading the data
/// Optional Parameter does not work as well. I Wish the optional parameter will work for this for the next version
///
/// Remember this is also Case sensitive
/// "_search":false,"nd":1289313832212,"rows":30,"page":1,"sidx":"Name","sord":"asc"
/// </summary>
/// <param name="page"></param>
/// <returns></returns>
[WebMethod]
[ScriptMethod]
public JqGridData LoadJqGridDataProductList(bool _search, int page, int rows, string sidx, string sord, int pCatId)
{
return LoadJqGridDataProductListProcess(_search, page, rows, sidx, sord, pCatId);
}

/// <summary>
/// This is the actual parameter
/// </summary>
/// <param name="isSearch"></param>
/// <param name="page"></param>
/// <param name="rows"></param>
/// <param name="sidx"></param>
/// <param name="sord"></param>
/// <param name="pCatId"></param>
/// <returns></returns>
private JqGridData LoadJqGridDataProductListProcess(bool isSearch = false,int page = 1,int rows = 30,string sidx = "", string sord = "", int pCatId = -1)
{
// int page = Convert.ToInt32(HttpContext.Current.Request["page"]);

try
{
//optimize it because using specific field
var lst = ProductRepository.FindAll();


//Generate jgGrid Rows
List<JqGridRow> gRows = new List<JqGridRow>();
List<object> cells = new List<object>();
foreach (var d in lst)
{
cells = new List<object>();
cells.Add(d.Active);
cells.Add(d.Name);
cells.Add(d.ProductID);
cells.Add(d.LastModifiedDate.ToString(CommonHelper.ShortDateTimeFormat));
gRows.Add(new JqGridRow(d.ProductID.ToString(), cells));
}

//Generate
return new JqGridData(1, 1, 1, gRows);

}
catch (Exception ex)
{
//just throw it at this time
throw ex;
}
return null;
}


}





 



Note: I wish this optional parameter will work for binding JSON object directly.




private JqGridData LoadJqGridDataProductListProcess(bool isSearch = false,int page = 1,int rows = 30,string sidx = "", string sord = "", int pCatId = -1)



Monday, November 01, 2010

Umbraco New Section Part 1

 

Here is the list of note for creating a custom section in Umbraco

Update Client Name

Change Umbraco/umbraco.aspx title

clip_image002

Change umbraco_client/application/umbracoApplicationAction.js

clip_image004

CUSTOM SECTION in UMBRACO

Creating Custom Section

(Icon)

- Update tray sprite icon image /umbraco/images/tray/traySprites.png
To Add a new icon, just insert 72 pixel of an icon

- Update CSS /umbraco/css/umbracoGui.css

/* CUSTOM TRAY */

.trayinventory{background-position: -18px -594px;}

/* END CUSTOM TRAY*/

Add Images for tree item

umbraco\images\umbraco\custom

(Database)

Add row in UmbracoApp

- Inventory

clip_image006

Add row in umbracoAppTree (to set up the tree)

clip_image008

Add User App Permission

clip_image010

need to setup the language so it will say Inventory instead of [Inventory]

Change umbraco/config/lang/en.xml
<area alias="sections">

<!-- Custom section -->

<key alias="inventory">Inventory</key>

<!-- End Custom Section-->

</area>

Fix undefined in the title ? (need to refresh javascript)

Add a task
Edit umbraco/config/create/ui.xml

<!-- CUSTOM SECTION -->

<nodeType alias="inventoryProduct">

<header>Product</header>

<usercontrol>/create/simple.ascx</usercontrol>

<tasks>

<create assembly="umbraco" type="userTasks" />

<delete assembly="umbraco" type="userTasks" />

</tasks>

</nodeType>

<nodeType alias="inventoryProductCategory">

<header>Product Category</header>

<usercontrol>/create/simple.ascx</usercontrol>

<tasks>

<create assembly="umbraco" type="userTasks" />

<delete assembly="umbraco" type="userTasks" />

</tasks>

</nodeType>

<!-- END CUSTOM SECTION -->