Intraweb has always been the preferred tool for Delphi to quickly develop web applications, but it has fewer controls and styles that are ugly. TMS and IW are available, but they are charged. For those of us who are used to free users, we want to find a crack. More strenuous. EasyUI is a framework based on JQuery. The built-in controls can fully meet the needs of our development of general web applications, and it is free and easy to use. Below I talk about how IW combined with the EasyUI development program to talk about some of their own experiences, and communicate with you. There are mainly the following methods:
First, the use of templates
in the IWForm using templates to introduce a good html file, combined with IW’s own controls for manipulation. Although this method is more convenient, the template also has its own shortcomings. The internal support of Chinese references is a big bug. At present, IW has no traces to be solved. If you must use the template, there are ways to circumvent it, that is, the Chinese characters use the web page to escape the “&#” plus the decimal code of the Chinese character. There are many articles for reference to the use of templates, and it is not the focus of this chapter, and will not be explained in detail.
Second, the MVC design pattern
IW uses the MVC method combined with the EasyUI design program, which is the focus of this article. We know that the interaction between IW and HTML static pages can be achieved through the javascript interface. You can use the AddToInitProc(‘alert(“Welcome”)’) statement or add a js statement to the control’s JavascriptEvent property. The method described in this article completely separates the interface from the data processing, and uses EasyUI to implement the interface (the IW’s visual control is completely unnecessary, the database control is still needed), and the data processing is given to the IW background. We develop these functions in a step-by-step manner by developing a simple application, and we will use a certain amount of space to introduce the use of some of the EasyUI controls (this article must have a certain javascript basis).
The first step: to achieve the login interface.
First introduce the following files, the other pages are also referenced like this, directly paste the code:

 <span style=”white-space:pre”> </span><link rel=”stylesheet” type=”text/css” href=”easyui/themes/default/easyui.css”>
<link rel=”stylesheet” type=”text/css” href=”easyui/themes/icon.css”>
<script type=”text/javascript” src=”easyui/jquery.min.js”></script>
<script type=”text/javascript” src=”easyui/jquery.easyui.min.js”></script>
<script type=”text/javascript” src=”easyui/locale/easyui-lang-zh_CN.js”></script>

 

These files must be quoted, easyui.css is the built-in style, icon.css is the various icons in use, easyui-lang-zh_CN.js is the Chinese file (EasyUI support for Chinese is still very good, if you feel Chinese Not good enough, you can open this file to modify it yourself). Interface section:

<form id=”ff” class=”easyui-form” method=”post” data-options=”novalidate:true”>
   <table cellpadding=”5″>
   <tr>
   <td>username:</td>
   <td><input class=”easyui-textbox” type=”text” name=”username” data-options=”required:true” style=”width:150px”/></td>
   </tr>
   <tr>
   <td>password:</td>
   <td><input class=”easyui-textbox” type=”password” name=”passw” data-options=”required:true” style=”width:150px”/></td>
   </tr>
   </table>
   </form>
   <div style=”width:216px;padding:5px 0px;height:30px”>
   <a href=”javascript:void(0)” class=”easyui-linkbutton” onclick=”submitForm()” style=”width:80px;float:left”>login</a>
   <a href=”javascript:void(0)” class=”easyui-linkbutton” onclick=”clearForm()” style=”width:80px;float:right”>cancel</a>
   </div>
   </div>
</div>

 

The login interface is basically completed, some are simple, and of course you can modify it yourself. The following implementation commits the data and clears the data, using Javascript:

function submitForm(){
$(‘#ff’).form(‘submit’,
url:’Login.php’,
onSubmit:function(){
return $(this).form(‘enableValidation’).form(‘validate’);
},
success: function(data){
if(parseInt(data)==1)
{
window.location=’main.html’;
}
else
{
$.messager.alert(‘Error’,’username or password error!’,’error’);
$(‘#ff’).form(‘clear’);
}
}
});
}
function clearForm(){
$(‘#ff’).form(‘clear’);
}
Save the file as “index.html”, that is, the home page, put it under wwwroot (note that the relevant files of easyui should also be placed in this directory). After starting the program, it is directly accessing this page, there is no “$” mark.
The login interface is basically completed, the data needs to be submitted to the “Login.php” page. According to the general method, create a new IWForm and use the template to load the file. This article uses another idea, which is also the key of this article:
Create a new unit with delphi Name the Login unit and join the IW project.
unit Login;interface
uses Classes, IW.Content.Base, System.SysUtils,HTTPApp, IWApplication, IW.HTTP.Request, IW.HTTP.Reply, IWMimeTypes;type
TLogin = class(TContentBase)
protected
function Execute(aRequest: THttpRequest; aReply: THttpReply; const aPathname: string; aSession: TIWApplication; aParams: TStrings): Boolean; override;
public
constructor Create; override;
end;
implementation
uses ServerController,UserSessionUnit;
{ TLogin }

constructor TLogin.Create;
begin
inherited;
mFileMustExist := False;
end;

function TLogin.Execute(aRequest: THttpRequest; aReply: THttpReply; const aPathname: string; aSession: TIWApplication; aParams: TStrings): Boolean;
begin
aReply.ContentType := MIME_HTML;
aReply.WriteString(‘data to client’);
Result := True;
end;

end.

uses
IWInit, IWGlobal, IW.Content.Handlers, Login;

procedure TIWServerController.IWServerControllerBaseConfig(Sender: TObject);
begin
THandlers.Add(”, ‘login.php’, TLogin.Create);
end;

Directly list the code, you can not quite understand what is going on, here is the process: the
client submits the username and password to “Login.php” through the Form, “Login.php” is a virtual file added by the server, mapped to the slave TContentBase inherits the implemented TLogin class, receives the submitted data with THttpRequest, and processes it, and writes the client data with THttpReply.writestring. In this way, the foreground and background code of the login process are completed.

The second step: to achieve the main interface
We developed a product information management program, the main interface with EasyUI Layout to implement adaptive browser (remember to introduce relevant js and css):

<div data-options="region:'north',border:false" style="height:60px;background:#B3DFDA;padding:0px 10px;text-align:center">
<h3>Demo system</h3>
</div>
<div data-options="region:'west',split:true,title:'catalog'" style="width:200px;padding:10px;">

</div>
<!–<div data-options=”region:’east’,split:true,collapsed:true,title:’East'” style=”width:100px;padding:10px;”>east region</div>–>
<div data-options=”region:’south’,border:false” style=”height:50px;background:#A9FACD;padding:10px;”>
</div>
<div data-options=”region:’center’,title:’details'”>

</div>

It is well understood, that is, the left west and the right east, the upper north and the lower south plus the central layout, the right side does not need, I commented it out.
  The page design idea is like this. Put a Tree on the left to display the product classification, and put GridData in the center to display the product information list, and delete, add, and modify functions through two controls.

  Add a Tree to this DIV in west:
<ul id=”easyui_tt” class=”easyui-tree”
data-options=”
animate:true,
lines:true,
url:’Treedata.php’,
method:’post’,
onClick: function(node){
QueryByID(node.id);
},
onContextMenu: function(e, node){
e.preventDefault();
$(this).tree(‘select’, node.target);
$(‘#mm’).menu(‘show’, {
left: e.pageX,
top: e.pageY
});
}”>
</ul>

 

  There are many attributes of Tree. One of the more important ones is node. The node of Tree has the following attributes for each node:

  id: Node ID, which is very important for loading remote data.
  Text: Displays the node text.
  State: node state, ‘open’ or ‘closed’, default: ‘open’.
  If it is ‘closed’, the node will not be expanded automatically.
  Checked: indicates whether the node is selected.
  Attributes: Custom attributes that are added to the node.
  Children: A node array declares a number of nodes. The node of the
  Tree is submitted by the url to the server to receive the returned data. The data of the formed
  tree is JSon format. We can analyze it:
[{
    “id”: 1,
    “text”: “Node 1”,
    “state”: “closed”,
    “children”: [{ //child node
        “id”: 11,
        “text”: “Node 11”
    },{
        “id”: 12,
        “text”: “Node 12”
    }]
},{
    “id”: 2,
    “text”: “Node 2”,
    “state”: “closed”
}]}

 

  With the above “login”, we inherit a TTreeData class from TContentBase to directly copy the template, modify one, pay attention to join the IW project, and map “TreeData.php” in the ServerController. We now need to implement the tree through delphi. The more layers of the tree, the more complicated it is. I found that
it is very troublesome to implement Tree dynamically regardless of the language. The EasyUI example can only implement two-layer tree. Reading Tree data from the database, there is a skill in database design, I don’t know how to deal with it, I am here to say a method: the upper and lower levels of the tree are represented by code, 2 digits represent the root, 4 digits The number represents the next level, and so on, the code can’t use pure numbers, so it’s not good to sort, I add a letter before the number, so you can arrange the upper and lower levels by “select*from Tree order by id”. Not sorted by code size. The database is not much to talk about, not in the scope of this article, you can see the database in my source code. The tree building code is as follows (I want to use JSon, I can’t learn less, I can only use string splicing):


function BuildTree:string;
var
 i,j,old_ln,new_ln:Integer;
 id,s,title,ft:string;
begin
ft:='{"id":"%s","text":"%s"},';//Json
with UserSession.FDQuery1 do
begin
  Open('select*from Tree order by id');
  s:='[';
  old_ln:=0;
  for i := 0 to RecordCount-1 do
    begin
       id:=Fields.Fields[0].AsString;
       title:=Fields.Fields[1].AsString;
       new_ln:=id.Length-3;
       if (new_ln=old_ln) then
          s:=s+Format(ft,[id,title]);
       if new_ln>old_ln then
          begin
            s:=s.Substring(0,s.Length-2);
            s:=s+Format(',"state":"closed","children":['+ft,[id,title]);
          end;
       if (new_ln<old_ln) then
          begin
            s:=s.Substring(0,s.Length-1);
            for j :=1 to (old_ln-new_ln) div 2 do
              s:=s+']}';
            s:=s+Format(','+ft,[id,title]);
          end;
      Next;
      old_ln:=new_ln;
    end;
end;
   s:=s.Substring(0,s.Length-1);
   for i := 1 to new_ln div 2 do
     s:=s+']}';
   result:=s+']';
end;


 

  The above code has been annotated. If there is anything we don’t understand, we can communicate again. We can implement N multi-level trees. As long as the client supports it, some controls do not support multi-level trees. Tree implementation, we then implement the right-click menu, onContextMenu:

onContextMenu: function(e, node){
e.preventDefault();
$(this).tree('select', node.target);
$('#mm').menu('show', {
left: e.pageX,
top: e.pageY
});

 

  Note that $(‘#mm’) is the JQuery identifier of the right-click menu. Let’s do a delete and add function. The code is as follows:
<div id=”mm” class=”easyui-menu” style=”width:120px;”>
<div onclick=”addnode()” data-options=”iconCls:’icon-add'”>Add</div>
<div onclick=”removeit()” data-options=”iconCls:’icon-remove'”>Delete</div>
</div>
  Hint: In many cases, EasyUI only needs to reference the $(”) similar identifier to add other controls. Implement addnode(), removeit(), and other features:

<span style=”white-space:pre”> </span>function appendn(r){
var t = $(‘#easyui_tt’);
var node =t.tree(‘getSelected’);
var pii=node.id;
$.ajax({
type : “post”,
url : “Treedata.php”,
data : {Action:’Add’,ID:pii,Title:r},
async : false,
success : function(data){
pii=data;
}
});
t.tree(‘append’, {
parent: (node?node.target:null),
data: [{id:pii,text:r}]
});
}
function removeit(){
var node = $(‘#easyui_tt’).tree(‘getSelected’);
var pii=node.id;
$.post(‘Treedata.php’,{Action:’Del’,ID:pii});
$(‘#easyui_tt’).tree(‘remove’, node.target);
}
function collapse(){
var node = $(‘#easyui_tt’).tree(‘getSelected’);
$(‘#easyui_tt’).tree(‘collapse’,node.target);
}
function expand(){
var node = $(‘#easyui_tt’).tree(‘getSelected’);
$(‘#easyui_tt’).tree(‘expand’,node.target);
}
function addnode(){
$.messager.prompt(‘Add’, ‘Input Name:’, function(r){
if (r){
appendn(r);
}
});
}
  This code is to use JQuery to submit data to IW, that is, submit data to the server $.post (‘Treedata.php’, {Action:’Del’, ID:pii}) in JSon format; submit delete function, which is $ Simple implementation of .ajax, by the way, in case the blog mentions
function TestPost(){
var mydata=”TestMYPost”;
executeAjaxEvent(“&data=”+mydata, null, “DoCallBack1”, false, null, false);
}
  This way to submit data, use WebApplication.RegisterCallBack(‘IWCallBack1’, DoCallBack1) to register the callback to receive data. I think it is easier to use JQuery’s post implementation. IWForm uses $.post inside:
$.post(GURLBase+”callback?”,
         {callback:”DoCallBack1″,data:”just test—–?”},
         function(data){processAjaxResponse(data);},”xml”);
}
  Note: GURLBase is equal to ‘/$/’ (look at the very bad dollar sign), modify the code in case:
function TestPost(){
var mydata=escape(“TestMYPost”);
executeAjaxEvent(“&data=”+mydata, null, “DoCallBack1”, false, null, false);//
}
This also supports Chinese.
  How the server handles the data, the login interface has been explained in detail, basically similar, add and delete is no longer listed code, you can directly look at my source code, using delphi to achieve really easy.
  After the Tree is finished, let’s talk about the DataGrid:
  Center this DIV to join:
<table class=”easyui-datagrid” style=”width:100%;height:400px”
data-options=”singleSelect:true,collapsible:true,fitColumns:true,url:’GridData.php’,
method:’post’,pageSize:10,pagination:true,onDblClickRow:onDClickRow”
toolbar=”#dg_tb”
id=”easyui_tb”>
<thead>
<tr>
<th data-options=”field:’codeID’,width:80,halign:’center’,editor:’text'”>ID</th>
<th data-options=”field:’p_name’,width:100,halign:’center’,editor:’text'”>Name</th>
<th data-options=”field:’p_type’,width:80,halign:’center’,align:’center’,editor:’text'”>Kind</th>
<th data-options=”field:’p_tid’,width:80,halign:’center’,align:’center’,editor:’text'”>Catalog</th>
<th data-options=”field:’p_pinpai’,halign:’center’,width:250,editor:’text'”>Brand</th>
<th data-options=”field:’p_price’,halign:’center’,width:60,align:’center’,editor:’text'”>Price</th>
<th data-options=”field:’p_discount’,halign:’center’,width:60,align:’center’,editor:’text'”>Discount</th>
</tr>
</thead>
</table>
<div id=”dg_tb” style=”padding:3px”>
<span>ID</span>
<input id=”codeID” class=”easyui-numberbox” style=”line-height:22px;border:1px solid #ccc”>
<span>Name</span>
<input id=”p_name” class=”easyui-textbox” style=”line-height:22px;border:1px solid #ccc”>
<a href=”#” class=”easyui-linkbutton” plain=”true” onclick=”doSearch()”>Query</a>
<a href=”javascript:void(0)” class=”easyui-linkbutton” data-options=”iconCls:’icon-add’,plain:true” onclick=”appendr();”>Add</a>
<a href=”javascript:void(0)” class=”easyui-linkbutton” data-options=”iconCls:’icon-remove’,plain:true” onclick=”remover()”>Delete</a>
<a href=”javascript:void(0)” class=”easyui-linkbutton” data-options=”iconCls:’icon-save’,plain:true” onclick=”acceptr()”>Modify</a>
<a href=”javascript:void(0)” class=”easyui-linkbutton” data-options=”iconCls:’icon-undo’,plain:true” onclick=”rejectr()”>Cancel</a>
</div>
DataGrid is powerful and complex. This article only covers basic applications. You can read the EasyUI help file I uploaded. Get the table data from the server side Same as above, the data is also in JSon format, build a MyGridData, leave the function in the above mentioned tree does not explain QueryByID (node.id), JS is as follows:
function QueryByID(id){
var tb=$(‘#easyui_tb’);
tb.datagrid({queryParams:{Action:’Q_ID’,ID:id}});
tb.datagrid(‘load’);
}
  Query data by ID is implemented on the server side like this:
function QueryData(config:string):string;
var
 arrjson:JSONArray;
 ajson:JSONObject;
 i,j:integer;
begin
  arrjson:=JSONArray.Create;
  ajson:=JSONObject.Create;
  with UserSession.FDQuery1 do
   begin
      Open(‘select*from product where ‘+config);
      for I :=0 to RecordCount-1 do
       begin
         for j := 0 to Fields.Count-1 do
            ajson.Put(Fields.Fields[j].DisplayName,Fields.Fields[j].AsString);
         arrjson.AddJSON(ajson.ToString(4));
         ajson.Clear;
         Next;
       end;
   end;
  Result:='{“total”:’+i.ToString+’,”rows”:’+arrjson.ToString(4)+’}’;
  arrjson.Free;
  ajson.Free;
end;
  I directly use the query conditions as parameters, so as to facilitate the extension, here yxdJson is used. In the control I uploaded, it is easier to use, in fact, it forms ‘{aaa:”BBB”, ccc:”DDDD”}’ The statement is particularly concise, without splicing strings (splicing strings is painful). I also want to use the data of Tree, but I can’t live or die, I have to give up. GridData is implemented by the server to achieve paging, but also very simple, that is, submit the page and rows these two parameters to the server, the code we download, the delphi implementation is also very simple, sql query to add limit (page-1) * rows, rows conditions Just fine. Note the transformation of strings and integers. Implement query, delete, add, modify functions, client js:

function doSearch(){
$('#easyui_tb').datagrid('load',{
Action:'Q_DN',
id: $('#codeID').val(),
p_name: $('#p_name').val()
});}
var editIndex = undefined;
var ExecType='';
function endEditing(){
if (editIndex == undefined){return true}
if ($('#easyui_tb').datagrid('validateRow', editIndex)){
var ed = $('#easyui_tb').datagrid('getEditor', {index:editIndex,field:'codeID'});
$('#easyui_tb').datagrid('endEdit', editIndex);
editIndex = undefined;
return true;
} else {
return false;
}
}
function onDClickRow(index){
if (editIndex != index){
if (endEditing()){
var  tt=$('#easyui_tb').datagrid('selectRow', index);
var EditID=tt.datagrid('getSelected')['codeID'];
tt.datagrid('beginEdit', index);
editIndex = index;
ExecType='update,'+EditID;
} else {
$('#easyui_tb').datagrid('selectRow', editIndex);
}
}
}
function appendr(){
if (endEditing()){
$('#easyui_tb').datagrid('appendRow',{p_discount:'1.0'});
editIndex = $('#easyui_tb').datagrid('getRows').length-1;
$('#easyui_tb').datagrid('selectRow', editIndex)
.datagrid('beginEdit', editIndex);
ExecType='insert into,';
}
}
function remover(){
var  tt=$('#easyui_tb').datagrid('getSelected');
if (tt==undefined) return;
var Delindex=$('#easyui_tb').datagrid('getRowIndex',tt);
var DelID=tt['codeID'];
$.messager.confirm('Delete','sure?',
function(r){ if (r){
$('#easyui_tb').datagrid('deleteRow', Delindex);
$.post('GridData.php',{Action:'delete',id:DelID});
}});
editIndex = undefined;
}
function acceptr()
if (endEditing()){
$('#easyui_tb').datagrid('acceptChanges');
if (ExecType=='') return;
var selrow=$('#easyui_tb').datagrid('getSelected');
var row=new Array();
if(selrow!=undefined)
row.push(selrow['codeID'],selrow['p_name'],selrow['p_type'],selrow['p_tid'],
        selrow['p_pinpai'],selrow['p_price'],selrow['p_discount']);
var param=ExecType.split(',');
if(param[0]=='update')
{
$.post('GridData.php',{Action:param[0],id:param[1],Rowdata:row.toString()},function(data){alert(data)});
}
if(param[0]=='insert into')
{
$.post('GridData.php',{Action:param[0],Rowdata:row.toString()},function(data){alert(data)});
}
ExecType='';
}
}
function rejectr(){
$('#easyui_tb').datagrid('rejectChanges');
ExecType='';
editIndex = undefined;
}
function getChanges(){
var rows = $('#easyui_tb').datagrid('getChanges');
return rows;
}
  The server implements these functions with the following function:
function Exec_SQL(act,id,row:string):string;

  The source code itself to see, very simple, is to operate the database. This article is basically completed, and finally talk about the unfinished function of this way: directly use http://xxx.xxx.xxx/main.html can enter the main interface without logging in, obviously not what we expected, can be in the main interface Adding the function of verifying login is also very simple. You can submit the verification information to login.php before the page is loaded. The code has been written, but the client has not added it. There is also the third big point.
  Third, dynamic loading
  Dynamic loading is simply that the client is still made separately, not under wwwroot, and you need to add a “/” in front of the path when referring to js and css. Still inheriting a class from TContentBase, implemented in a function like this:

function TMyIndex.Execute(aRequest: THttpRequest; aReply: THttpReply; const aPathname: string; aSession: TIWApplication; aParams: TStrings): Boolean;
var
 ss:Tstrings;
begin
  aReply.ContentType := MIME_HTML;
  ss:=TstringList.create;
  ss.loadformfile('static html');
  aReply.WriteString(ss.text);
  ss.free;
  Result := True;
end;

  This is obviously safer. You can verify the presence or absence of login before loading the main interface. You can also add some similar templates to replace the identifiers in the loading page. When loading dynamically, replace these identifiers with the content that needs to be displayed on the page to implement the header. Body and footer are shared.
  Tools used for this article: delphiXE7+Intraweb 14.0.38