One, two, three
As mentioned earlier, the method declaration is:
@SFCUI.AjaxValue(story.ID, effortValue.ToString(), Effort.EffortPlannedValues, "/SFC/Efforts/AjaxSetEffortPlanned?itemID=" + story.ID + "&value={0}", ajaxOnSuccess: "refreshLeftPad");
Call example:
@SFCUI.AjaxValue(story.ID, effortValue.ToString(), Effort.EffortPlannedValues, "/SFC/Efforts/AjaxSetEffortPlanned?itemID={0}&value={1}", ajaxOnSuccess: "refreshLeftPad");
How can I implement toggle, pop-up menu, and updatetargetid?
This is an important principle of design: hiding all technical details inside the implementation.
Internal Function Design
The following code is only used as an example. It is not the same as what I use. It is simplified to illustrate the problem.
Public static mvchtmlstring ajaxvalue (int id, string value, string [] values, string urlformat, string ajaxonsuccess = NULL) {string ajaxupdatetargetid = "valueof" + ID; string innerhtml = NULL; // build the DIV to show the final value. tagbuilder thevalue = new tagbuilder ("Div"); // This is the DIV where the original value is placed. It is also updated in the future, and the ID is generated before it. Thevalue. innerhtml = value ;... // build the ajaxlink to popup the menu of values to be selected. tagbuilder ajaxlink = new tagbuilder ("Div"); // This is a small picture behind the value. Click it to bring up the menu... ajaxlink. addcssclass ("clickshow"); // This is a class defined by myself. When you click it, something will pop up, that is, $ ("# clickshowbodyofajaxlinkof" + $ (this ). ATTR (ID )). show (). Innerhtml + = ajaxlink. tostring (); // build the DIV to show the popup menu; and a "clickshowbody" container to hide the menu when mouse left. tagbuilder content = new tagbuilder ("Div"); // This is a menu that is hidden at ordinary times and displayed after you click it.... // There are many hidden functions here, because I have called many of my own functions, such as imagelink (), and I cannot write them out.... // Roughly: In the menu, foreach (var v in values) uses ID and each V, String. Format (urlformat, ID, v) to generate an ajaxlink.... // If onsuccess is not null, remember to put onsuccess in ajaxlink.... // Key code: imglink (A tagbuilder ). mergeattribute ("onclick", "sys. MVC. asynchyperlink. handleclick (this, new sys. UI. domevent (event), {insertionmode: SYS. MVC. insertionmode. replace, updatetargetid: '"+ ajaxupdatetargetid +"', onsuccess: function. createdelegate (this, "+ ajaxonsuccess +")}); "); innerhtml + = clickshowbody. tostring (); return New mvchtmlstring (innerhtml );}
In this way, the DIV placed in the value will be updated in the function) the pop-up menu, what should be written on the pop-up menu, what should be done after clicking, what should be done after the pop-up menu, and so on, all of which should be done.
The following figure shows the pop-up effect after clicking:
More complex interfaces
The above example basically solves the problem of a simple pop-up window with a simplified style. What if the pop-up is complicated? For example, if I want to assign a task to a group in charge or to a member in the group I participate in, and do not want these Members to be directly listed by name (assuming I cannot remember these members ), we hope to present the following interface:
Click the person name in the figure to assign the task to this person.
At this time, do not first think about technical implementation means, but first think about: How many business information is there to deal? Actually there are four:
1. Which task? Task ID
2. What information should I change? "Current Owner"
3. What are the optional personnel? "My group (I am responsible for managing and participating )"
4. What should I do if I have set it? "Refresh the screen" (mainly to make the updated content accept the JS refresh in document. Ready)
So the function declaration is:
public static MvcHtmlString AjaxSDCValue(Item item, int sdcTypeValue, AjaxValue.ValuesKeys valuesKey, string ajaxOnSuccess = null)
Item is the task
Sdctypevalue is the value of the previously defined custom field (not defined for this ajaxvalue, SDC = system defined Column System Custom field)
Ajaxvalue. valueskey is a slightly more complex enum. Previously, we always directly input string [] to represent future values. Now it may be user []… So simply pass an Enum and the function internally determines what to look for this time, and then process it in detail.
Where is urlformat? Because ajaxsdcvalue is used to process custom system fields, urlformat is uniform. Please refer to the internal function:
public static MvcHtmlString AjaxSDCValue(Item item, int sdcTypeValue, AjaxValue.ValuesKeys valuesKey, string ajaxOnSuccess = null) { string value = item.ReadSDCValueOf(sdcTypeValue); string urlFormat = "/SFC/Items/AjaxSetSDCValue?<itemID={0}&sdcTypeValue=" + SDCType.USER_CURRENT_OWNER+ "&value={0}"; return AjaxValue(item.ID, value, valuesKey, urlFormat, ajaxOnSuccess); }
In fact, the original function ajaxvalue can be fully used, but too many technical details are exposed to the user (especially the urlformat format is too complex), and users should not care about it.
/SFC/items/ajaxsetsdcvalue sets the user_current_owner field of item to the value.
Where is the complex menu displayed?We have summarized that the following things may pop up in ajaxvalue:
1. The most basic string (the original string [], which can process available estimated values, remaining time values, and consumed time values ......)
2. My team members (assign tasks, assign bugs, schedule duty, schedule vacations ......)
3 .......
Urlformat has different functions after clicking, but the structure and appearance of the preceding menu are the same each time.
Therefore, an ajaxcontroller. popupajaxvaluesmenu is created. The Enum of ajaxvalue. valueskey is used to determine which menu is displayed (including the data in the prepared menu), and urlformat is also uploaded.
Review
It took two days to design and debug this pile of things, but you no longer need to see about 50 lines of C #/html code each time.
When future maintainers see this Code:
@SFCUI.AjaxSDCValue(Story, SDCType.USER_CURRENT_OWNER, AjaxValue.ValuesKeys.UsersMyTeams, ajaxOnSuccess: "function() { refreshStoryPad(" + Story.ID + "); }", imageUrl: "/SFC/Users/Details16.png")
He will think: "Oh, Here we want to adjust the story currentowner ...... A person in my team will refresh this story if it succeeds. In addition, an avatar icon appears in the front !"
This is much more comfortable than the 50 lines of code.
Finally, I suddenly remembered another sentence I had summarized 10 years ago:
The highest level of encapsulation is to write the call code with the same amount of text as the natural language, and the rest is hidden.