C++Builder 5 Developers Guide
For the master-detail overview, we must create a WebSnap data module, so we can actually add some datasets to connect to real-world data (the customer and orders tables). So, click File, New ”Other again, and select the WebSnap Data Module from the WebSnap tab of the Object Repository. This will present us with a dialog for a New WebSnap Data Module. If we just leave it at the default settings and click OK, a new WebSnap data module has been added to our WebSnap project. We should now drop any datasets on this data module, such as two regular TClientDataSet components from the Data Access tab of the C++Builder 6 Component Palette. Rename the ClientDataSet components to cdsCustomer and cdsOrders , and connect their filename property to C:\Program Files\Common Files\Borland Shared\data\customer.xml and orders.xml . Now save the data module in file wDataMod.cpp (make sure it ends up in the project directory, and not in the data directory again).
Right-click both ClientDataSet components and start the fields editor. Right-click again and make sure to Add all fields (you can remove any field from that list, but make sure to leave the CustNo and OrderNo fields because we need them in a moment). Now we need a TDataSource component, pointing to the cdsCustomer dataset, to create a master-detail relationship. Assign the DataSource to the MasterSource property of the cdsOrders dataset, and then click the ellipsis next to the MasterFields property, so we can assign this to the CustNo fields of both datasets.
Primary Key
We already saw that to enable the WebSnap client application to maintain its own state, we must now specify a primary key field (one that the client can use to tell the WebSnap server which record we want to be working on). For the cdsCustomer dataset, we must select the CustNo field, so go to the Object Inspector, open the ProviderFlags property and set the pfInKey subproperty value to true . For the cdsOrders dataset, we must do the same for the OrderNo field.
DataSetAdapter
Now that the cdsCustomer and cdsOrder datasets are ready, it's time to drop two TDataSetAdapter components from the WebSnap tab of the component palette; call them dsaCustomer and dsaOrders ”see Figure 22.24. The DataSet property of dsaCustomer should point to the cdsCustomer dataset, and dsaOrders should point to cdsOrders .
Figure 22.24. WebSnap Data Module.
Go to the Object Treeview, select the DataSetAdapters and right-click the Actions property to add all possible Actions. Do the same with the Fields property, so we have adapter fields for every field in the two ClientDataSets . Now, although the cdsOrders is already configured to be a detail of the cdsCustomer master table, we still need to specify that the dsaCustomer is a MasterAdapter of the dsaOrders . We can do this by assigning dsaCustomer to the MasterAdapter property of dsaOrders .
This is again a very important moment in your design. If you want to remove some fields from your view (from the view that will be represented by a particular DataSetAdapter ), you should remove these fields from the DataSetAdapter . If there are some fields that you don't ever want to use, you should remove them from the persistent field list of the ClientDataSet ”and not wait until they appear in the DataSetAdapter field list.
For the list of actions you should also consider carefully which actions you want to allow (that is, make available) for the end users, using this particular DataSetAdapter . You might have correctly guessed by now that you can actually have more than one DataSetAdapter connected to a (Client)DataSet , each of these different DataSetAdapter components corresponding to a different view (showing potentially a different set of fields, with potentially a different set of actions to apply on these fields).
WebSnap Page Module
Now that we have a master-detail relationship between the ClientDataSets (and even the DataSetAdapters ), it's time to create a new WebSnap Page Module to show the actual data. Click File, New ”Other, go to the WebSnap tab, and double-click the WebSnap Page Module icon. Because we want to use the DataSetAdapters , we must change the Producer Type from a regular PageProducer to an AdapterPageProducer (as usual). Apart from that, you will probably want to change the name (and, hence, the title as well) to something like Customer , see Figure 22.25.
Figure 22.25. New WebSnap Page Module.
The final option that you need to check is the Login Required field. This will make sure that we won't be able to get to this page unless we're logged into the system. We'll see this in a moment.
When you click OK, the new Page Module is created, including an AdapterPageProducer component. Save this new unit in file pmCustomer.cpp , and press Alt+F11 to include the header of the wDataMod unit, so we can access the DataSetAdapters on the data module.
Next, double-click the AdapterPageProducer to start the Web Page Editor again. This time, we're going to build a master-detail output form. In the Web Page Editor, we can always right-click a component to get the New Component dialog that will produce subcomponents. First, we need to add an AdapterForm under the AdapterPageProducer . Then, an AdapterCommandGroup , AdapterFieldGroup , and AdapterGrid under the AdapterForm . Now we have three design time warnings, that should be easy to fix. The AdapterCommandGroup should have its DisplayComponent property point to the AdapterFieldGroup . The AdapterFieldGroup should have its Adapter property point to the WebDataModule1->dsaCustomer (the master table). The AdapterGrid should have its Adapter property point to WebDataModule1->dsaOrders (note that the DataSetAdapters are coming from WebDataModule1 , which is the reason that the header of unit wDataMod must be included, or else you won't be able to find the two DataSetAdapters to use). The final results should be as shown in Figure 22.26.
Figure 22.26. Customer-Orders data at design time.
Note that the buttons are again very wide (just like in the first example shown in Figures 22.10 and 22.11). Fortunately, we can do something about that. Go to the Web Page Editor, right-click the AdapterCommandGroup and Add All Commands. Now, for each command button, go to the Object Inspector and change the Caption property. Remove all Row from the button captions to result in a much nicer view as can be seen in Figure 22.27.
Figure 22.27. Final Customer-Orders data at design time.
It's time to compile the application and run it. As you will see, the Home page contains four links (to Home, Login, Birthday, and Customer) as well as a link to the Login page in the upper-left corner. This means that the visitor can decide to Login at any time during the session (not only when it's needed). Let's not login right away, but just click the Customer link (which requires Login).
As can be expected, we do not end up on the Customer page, but rather on the Login page. We have to specify our User (Name) and Password here, and the NextPage is already preselected with the Customer page that we wanted to go to, see Figure 22.28. How nice!
Figure 22.28. WebSnap Login page of WAD.
Just enter the correct User and Password, click Login and you'll end up in the Customer page. If you didn't specify the correct Password (or an unknown User), you'll get an error message presented in the same Login page (because we made sure to point the AdapterErrorList back to the LoginFormAdapter ). Right now, the error message is presented below the Login button, which can be fixed (if you want) by moving the AdapterErrorList higher in the list of subcomponents from the AdapterForm on the Login Page Module.
If you've logged in correctly, you get a view of the Customer-Orders overview on the Customer page (note that I'm afraid it isn't possible to see the details in Figure 22.29, but believe me ”they're there).
Figure 22.29. WebSnap Customer page of WAD.
Linking Pages by Name
So far, we've only seen the main master page, with the details listed on the same page (although the page was a bit long to show all details in the same screen shot). However, sometimes you want to have a special page for the masters only, and then use buttons to link to pages that show the single master and all details.
For this I want to create two more new TWebPageModules : one for the master (customer) table, displayed in a grid-like output, and one for the master and details (customer-orders) displayed in a field group for the master and grid for the details. We've just made the latter, but let's make the former now (the customers in a grid), including a link from one page to another.
Click File, New ”Other and select the WebSnap Page Module Wizard to add yet another Page Module to our project. Make sure to select the AdapterPageProducer again, and call it Customers (instead of the previous one, which was called Customer ”showing a single customer at a time, instead of all customers). Also, don't forget to check the Login Required option as well as the Published option.
After you've created the new WebSnap Page Module, save it in pmCustomers.cpp and make sure to press Alt+F11 to include the header of the WebSnap Data Module (in wDataMod ), so you can access the dsaCustomers TDataSetAdapter . This is a very convenient way to authorize users and actions with the Customer data.
Next, double-click the AdapterPageProducer to start the Web Page Editor again. This time, we're going to build a master grid-output form. Right-click in the Web Page Editor to add an AdapterForm under the AdapterPageProducer . Then, add an AdapterCommandGroup and AdapterGrid under the AdapterForm . We get two design time warnings, which are easy to fix (as always). The AdapterCommandGroup should have its DisplayComponent property point to the AdapterGrid . The AdapterGrid should have its Adapter property point to WebDataModule1->dsaCustomers (one of the DataSetAdapters from WebDataModule1 , and the reason that the header of wDataMod must be included), resulting in Figure 22.30.
Figure 22.30. Customers data at design-time.
Now, as you can see from Figure 22.30, there are far more buttons that I want to see. In fact, I would never want to enable the user to edit anything inside an AdapterGrid display. So, select the AdapterCommandGroup , right-click it, and make sure to select only the Components (buttons) for the Actions you want such as FirstRow, PrevRow, NextRow, LastRow, and BrowseRow.
The new design time output is getting closer to what we want already, see Figure 22.31.
Figure 22.31. Customers data at design-time.
Apart from removing some of the buttons, we should also consider removing some of the fields. Especially because I want to add a special command button (to view the details) in the last column ”which currently is out of view. To do this we must not only remove some dataset fields, but also add a new column to the AdapterGrid . Right-click the Adapter Grid, do Add All Columns, and then remove the columns you don't need (leaving only the CustNo, Company, City, Country, and Contact fields, for example), see Figure 22.32.
Figure 22.32. Add All Columns.
After that, it's time to add a new column to the AdapterGrid , so right-click the AdapterGrid , select New Component, which gives us a dialog with three choices: AdapterCommandColumn (displaying a button), AdapterDisplayColumn (displaying a field value), or AdapterEditColumn (giving the option to edit a value), see Figure 22.33.
Figure 22.33. Add New Column.
Clearly, we need the AdapterCommandColumn , so add that one. Warning: Your display might look ugly once again because by default the new AdapterCommandColumn will show all available AdapterActions . To fix this, just select the AdapterCommandColumn component and right-click on it to add the only action you want (this time don't do an Add All Command, but only do an Add Command) and select the BrowseRow Command which is the easiest to use in this situation.
Select the BrowseRow button, go to the Object Inspector and specify the name of the Customer (single value) Page Module in the PageName property. This will make sure that whenever we click the BrowseRow button, we will jump to the Customer Page Module, within the context that we were (that is, the current row in which the button was shown).
Finally, make sure the buttons get some nicer captions (such as Details for the BrowseRow button), and the final output at design time can be seen in Figure 22.34.
Figure 22.34. Final output.
If you save your work, recompile it, and run it, you can use the Web App Debugger again to view the WebSnap application in action. Whenever you click the Details button, you will jump to the master-detail page with the complete information of the customer and orders database, including the option to click the Edit button at that location to change the data, if you want.
Tweaking and Turning
Now, let's do some final tweaking and turning before it's time to wrap this topic (follow-up articles on WebSnap will be published on my Web site at http://www. drbob42.com/CBuilder). The first thing I want to do is to actually hide the Customer Page Module because we now have a Customers Page Module with a Grid as a new entrance (so no need to show both the Customer and Customers page from the top-level menu). But when we created both Page Modules, we checked the Published option already. So, how can we unpublish a WebSnap Page Module? Fortunately, that's not too difficult. For our example, open the file pmCustomer.cpp and go to the last line. Now, place the << wpPublished option in comments, which will unpublish the page module:
static TWebPageInit WebInit(__classid(TCustomer), crOnDemand, caCache, PageAccess /* << wpPublished */ << wpLoginRequired, ".html", "", "", "", "");
If you recompile and run the WebSnap application again, you will notice that the Customer menu is gone, but you can still get there using the Details button on the Customers page. Exactly the way I want it.
Final Deployment
Although the Web App Debugger application is really nice to debug and test without the need for a real Web server, it is not a result that you can deploy. In fact, you can deploy any target except for the Web App Debugger project. Fortunately, you can just start another WebSnap application, remove the intial Application Module, and move all units (except for the first empty main form) over to this new WebSnap application. If you do this in a project group, you can even work on the WebSnap projects at the same time, sharing the WebSnap data and page modules among the different targets. Take a look at the CBuilder6\Examples\WebSnap directory for the example projects that are all available as ISAPI DLLs and as Web App Debugger executables.
|
Top |