NotificationPreferences
TsgcHTMLComponent_NotificationPreferences: a table with one row per category and one checkbox per channel (in app, push, email), in Delphi, C++ Builder and .NET. Your application loads and saves the values.
TsgcHTMLComponent_NotificationPreferences: a table with one row per category and one checkbox per channel (in app, push, email), in Delphi, C++ Builder and .NET. Your application loads and saves the values.
The library stores nothing. OnLoadPreferences asks your application for the values of one user, OnSavePreferences hands back what the user ticked, and persisting it is your job. The values are name=value pairs with 1 or 0, and every offered pair is always present. It works on every edition.
TsgcHTMLComponent_NotificationPreferences (unit sgcHTML_Component_NotificationPreferences)
A table: one row per category, one checkbox per channel, and a save button
Delphi, C++ Builder, .NET
Add one item to Categories for each thing a user can be told about, answer OnLoadPreferences from your own storage, persist what arrives in OnSavePreferences, and route the posted form into ProcessAction with the user taken from the session.
uses
sgcHTML_Session, sgcHTML_Component_NotificationPreferences;
var
oPrefs: TsgcHTMLComponent_NotificationPreferences;
begin
oPrefs := TsgcHTMLComponent_NotificationPreferences.Create(nil);
try
oPrefs.PreferencesID := 'prefs';
oPrefs.Title := 'How you want to hear about it';
oPrefs.SaveCaption := 'Save preferences';
with oPrefs.Categories.Add do
begin
Name := 'orders';
Caption := 'A new order arrives';
end;
with oPrefs.Categories.Add do
begin
Name := 'billing';
Caption := 'A payment fails';
end;
oPrefs.OnLoadPreferences := PrefsLoad;
oPrefs.OnSavePreferences := PrefsSave;
// the user comes from the session, never from the form
oPrefs.LoadPreferences(sgcHTMLRequestSession.UserID);
Response := oPrefs.HTML; // one row per category, one checkbox per channel
finally
oPrefs.Free;
end;
end;
// the application owns the values: one category.channel=1 or =0 per pair
procedure TMain.PrefsLoad(Sender: TObject; const aUserID: string;
aValues: TStrings);
begin
aValues.Add('orders.inapp=1');
aValues.Add('orders.push=0');
aValues.Add('orders.email=1');
end;
procedure TMain.PrefsSave(Sender: TObject; const aUserID: string;
aValues: TStrings);
var
i: Integer;
begin
// every offered pair is here, with 1 or 0
for i := 0 to aValues.Count - 1 do
MyStore.Save(aUserID, aValues.Names[i], aValues.Values[aValues.Names[i]] = '1');
end;
// in the message handler that receives the form the table posts
if oPrefs.ProcessAction(vUser, vAction, vPostedFields) then
oHTMX.PushFragment(vGuid, oPrefs.HTML);
// includes: sgcHTML_Session.hpp, sgcHTML_Component_NotificationPreferences.hpp
TsgcHTMLComponent_NotificationPreferences *oPrefs = new TsgcHTMLComponent_NotificationPreferences(NULL);
try
{
oPrefs->PreferencesID = "prefs";
oPrefs->Title = "How you want to hear about it";
oPrefs->SaveCaption = "Save preferences";
TsgcHTMLPreferenceCategory *orders = oPrefs->Categories->Add();
orders->Name = "orders";
orders->Caption = "A new order arrives";
TsgcHTMLPreferenceCategory *billing = oPrefs->Categories->Add();
billing->Name = "billing";
billing->Caption = "A payment fails";
oPrefs->OnLoadPreferences = PrefsLoad;
oPrefs->OnSavePreferences = PrefsSave;
// the user comes from the session, never from the form
oPrefs->LoadPreferences(sgcHTMLRequestSession()->UserID);
String html = oPrefs->HTML; // one row per category, one checkbox per channel
}
__finally
{
delete oPrefs;
}
// the application owns the values: one category.channel=1 or =0 per pair
void __fastcall TMain::PrefsLoad(TObject *Sender, const String aUserID,
TStrings *aValues)
{
aValues->Add("orders.inapp=1");
aValues->Add("orders.push=0");
aValues->Add("orders.email=1");
}
void __fastcall TMain::PrefsSave(TObject *Sender, const String aUserID,
TStrings *aValues)
{
// every offered pair is here, with 1 or 0
for (int i = 0; i < aValues->Count; i++)
MyStore->Save(aUserID, aValues->Names[i], aValues->Values[aValues->Names[i]] == "1");
}
// in the message handler that receives the form the table posts
if (oPrefs->ProcessAction(vUser, vAction, vPostedFields))
oHTMX->PushFragment(vGuid, oPrefs->HTML);
using esegece.sgcWebSockets;
var prefs = new TsgcHTMLComponent_NotificationPreferences();
prefs.PreferencesID = "prefs";
prefs.Title = "How you want to hear about it";
prefs.SaveCaption = "Save preferences";
var orders = prefs.Categories.Add();
orders.Name = "orders";
orders.Caption = "A new order arrives";
var billing = prefs.Categories.Add();
billing.Name = "billing";
billing.Caption = "A payment fails";
prefs.OnLoadPreferences += PrefsLoad;
prefs.OnSavePreferences += PrefsSave;
// the user comes from the session, never from the form
string user = sgcHTMLSessionHelpers.sgcHTMLRequestSession()?.UserID ?? "";
prefs.LoadPreferences(user);
string html = prefs.HTML; // one row per category, one checkbox per channel
// the application owns the values: one category.channel=1 or =0 per pair
void PrefsLoad(object sender, string userID, List<string> values)
{
values.Add("orders.inapp=1");
values.Add("orders.push=0");
values.Add("orders.email=1");
}
void PrefsSave(object sender, string userID, List<string> values)
{
// every offered pair is here, with 1 or 0
foreach (var line in values)
{
int eq = line.IndexOf('=');
myStore.Save(userID, line.Substring(0, eq), line.Substring(eq + 1) == "1");
}
}
// in the message handler that receives the form the table posts
if (prefs.ProcessAction(user, action, postedFields))
htmx.PushFragment(guid, prefs.HTML);
The members you reach for most often.
Categories is a TsgcHTMLPreferenceCategories collection; each TsgcHTMLPreferenceCategory has a Name, the stable key used in the values and as the name of the checkbox, and a Caption, which is what the user reads and is escaped when it is rendered. An empty Caption falls back to the Name, and a category with an empty Name is skipped. IndexOfName finds one.
Channels chooses which of ncInApp, ncPush and ncEmail get a column, all three by default. The channel names are shared with TsgcHTMLComponent_Notification, which asks your application for them in OnGetChannel before it delivers anything.
Values are name=value pairs, one per offered category and channel: orders.inapp=1, orders.push=0, orders.email=1. The key is the category Name, a dot, and the channel key inapp, push or email. A value is 1 when the channel is on and 0 when it is off. ValueKey(aCategory, aChannel) builds the key.
LoadPreferences(aUserID) clears Values and fires OnLoadPreferences(aUserID, aValues): fill aValues with the category.channel=1 lines of that user. Values is a read-only view of what is rendered, or of what was last saved. A pair you leave out is shown unticked.
OnSavePreferences(aUserID, aValues) receives every offered pair with its new value, so your application never has to guess what an absent key meant. SavePreferences(aUserID, aPosted) takes the form as it arrived, where only the ticked boxes are present, and ProcessAction(aUserID, aAction, aPosted) routes it, returning False when the action is not prefsSave.
The saved form travels as data sent by the client, so no user id is written into the markup, and anything that names a category or a channel the component does not offer is ignored. A forged form cannot widen the preference set. The component enforces no authorization: take the acting user from the request session (sgcHTMLRequestSession), never from the form.
IsChecked(aCategory, aChannel) tells whether a pair is on, SetChecked(aCategory, aChannel, aValue) writes 1 or 0 into Values, and IsOffered(aCategory, aChannel) is True when the category exists and the channel has a column.
PreferencesID is the id of the root element and the value posted in the prefs field, so a page with several tables knows which one answered. Title, SaveCaption and EmptyText set the texts, and ShowSave (on by default) shows the button. The form posts prefsSave as a data-sgc-ws-send form, with one category.channel field set to 1 per ticked box.
The unit compiles when SGC_HTML is defined, which sgcVer.inc does not do for Android and iOS. It works on every edition, and sgcHTML is a standalone pack, sold independently of sgcWebSockets. The push checkbox only records a choice: delivering a push needs WebPush, which is available only in the Enterprise and All-Access editions.
The notifications themselves are shown by NotificationInbox, and Notification decides whether a user is told in the page or by a push.
| Online HelpFull API reference and usage guide for this component. | Open | |
| All sgcHTML ComponentsBrowse the full feature matrix of 80+ components. | Open | |
| Download Free TrialThe 30-day trial ships the 60.HTML demo projects, including 17.FieldService, which uses the preferences table. | Open | |
| PricingSingle, Team and Site licenses with full source code. | Open |