Say you have several webparts, one as a controller and several which take information from the controller and act on it. This is fairly easy to model using the Consumer/Producer interface introduced in ASP 2.0.
How would you be able to add interactions the other way around whilst still maintaining the above?
A simple example would be: the user enters information into webpart A which performs a search and the results would be displayed on webpart B. Webpart C allows you to filter the results which should trigger webpart A to re-submit the query and hence update the results in B.
It doesn't seem possible to do in WSS 3.0 because you are only allowed 1 interface to be used in all of the connections at any one time.
Does this even make sense ? :-)
A quick and dirty solution to enable arbitrary control communication is to use recursive find control and events. Have the controls search the control tree by control type for what they need and then subscribe to publicly exposed events on the publishing control.
I have previous used the trick to enable standard server controls to find each other when embedded in CMS systems from different vendors to avoid a specific communication API entirely.
I don't see anything wrong with webpart A getting a reference to webpart B and calling public/internal methods/properties or subscribing handlers to public/internal events. One point of mention when doing this though: EnsureChildControls. I have witnessed with my own eyes one webpart being run clear to PreRender while another webpart hadn't even run CreateChildControls.
From webpart A, fetch your reference to webpart B (in this case webpart B is of type Calendar) like so:
private Calendar _calendarWP = null;
public Calendar CalendarWP
{
get
{
if (_calendarWP != null)
return _calendarWP;
else
foreach (System.Web.UI.WebControls.WebParts.WebPartZone zone in this.WebPartManager.Zones)
foreach (System.Web.UI.WebControls.WebParts.WebPart webpart in zone.WebParts)
if (webpart is Calendar)
{
_calendarWP = (Calendar)webpart;
_calendarWP.EnsureChildControls();
return _calendarWP;
}
return null;
}
}
Now you can do things like fetch some new data and update the Calendar like so:
IEnumerable newData = SomeDataProvider.GetNewData(args);
CalendarWP.someGridView.DataSource = newData;
CalendarWP.someGridView.DataBind();
Or perhaps let webpart A toss a reference to itself over to webpart B so it can use webpart A's public/internal properties to go fetch data for itself:
CalendarWP.UseWPAToFetchData(this);
Related
I have a site that is running on drupal 7 and uses civicrm 4.4.1. I need the events to be included in the search results.
So far all I have found was dated documentation on civicrm that required modules that are not available for Drupal 7.
I also tried the search page module and it is not grabbing the events.
It's a little unclear what you're looking for, so I'll answer two ways.
You can search for event participants most easily by going into the Search menu and selecting Advanced Search. You can see the events information by clicking on the Events header--the section will open up. You don't need to enter anything else on the search form unless you want to search for that too (i.e. fundraiser attendees who live in West Virginia).
If you want CiviCRM events to show up in your Drupal content search results, you'll need to get the events to appear as content. CiviCRM information is 100% separate from Drupal content, but you may have some luck using the CiviCRM Entity module https://drupal.org/project/civicrm_entity to expose CiviCRM events as entities.
I haven't seen anything pre-built that will include CiviCRM events in the standard Drupal site search. Looking at the search api, I think it is possible to create a module to do that, but I don't think it is trivial. I haven't written any modules for the search api, but it seems like there is a bit of bookkeeping to be done to write this kind of integration.
I've handled this in a couple of ways for my customers. One, create a content type for Events and put a detailed description and basic date information in the content type. When creating events in CiviCRM, just make a barebones event for registration and link to the event registration page directly from the event node. Two, make event search a separate action, with a nice link and a view.
I know that neither of these solutions is ideal, but I don't see a quick solution apart from writing your own search plugin.
We create content in Drupal and link it to Civi event pages using a Computed Field that matches Event Name to the node's Title field, and Event Start Date to the node's Event Date field. Sample code for the Computed Field:
list($id, $vid, $bundle) = entity_extract_ids($entity_type, $entity);
$query = "SELECT
ce.id
FROM {node} n
INNER JOIN {field_data_field_event_date} de ON n.nid = de.entity_id AND n.vid = de.revision_id
INNER JOIN {civicrm_event} ce ON n.title = ce.title COLLATE utf8_unicode_ci
AND ce.start_date = convert_tz(field_event_date_value,'GMT','America/New_York')
WHERE n.nid = :nid
AND n.vid = :vid
LIMIT 1";
$result = db_query($query,
array(':vid' => $vid, ':nid' => $id))->fetchField(0);
if ($result === NULL || $result == "")
{
$entity_field[0]['value'] = 0;
}
else
{
$entity_field[0]['value'] = $result;
}
Then you can use a bit of display code like this:
if ($entity_field_item['value'] == 0)
{
$display_output = '';
}
else
{
$display_output = 'Buy tickets';
}
Since we have the Civi event code saved to the node, we can also use any native Drupal search or Views functionality, and get creative in Drupal templates as needed. Other options could be to write your own module that does something like this, or consider using the Civi REST endpoint /sites/all/modules/civicrm/extern/rest.php?entity=Event&action=getlist&json={"sequential":1}&api_key=yoursitekey&key=yourkey with Drupal Feeds and Feeds Extensible Parsers modules for a solution that creates and updates the Drupal events with minimal code required.
I'm just starting to use sharepoint designer and realised there's a lot that can be done to extend the basic features in sharepoint. We have an email alert sent out when a new task is created (by the user) and I want to customise the email so that it also includes a link called 'Assign'. When clicked, I want this link to automatically update the task with the assigned to field for the person that clicked it.
So I think the way to do this would be to hard-code the assign to value in the url behind this link, but I have no idea if this is possible or if there is an easier/better way to do this.
Any advice would be appreciated as I'm a complete beginner.
thanks.
I will not cover "How to modify the contents of an eamil alert" here as that is a seperate question and there are a lot of articles that cover that already.
For the Assigned link :-
You would need to create a custom page (or web part on an existing page) as the destination of your Assign link - this would take the Task ID as a query string param and then update the assigned to with the current user.
You could make this flexible by also taking the ListID but you may want to think about how this could be abused and put appropriate measures in place.
EDIT - in response to comment.
This is top of my head, not checked in compiler. This would have to sit on the same server as SharePoint to work as its using the OM - if you want to use a different server (why would you though) then look in the web services.
private void updateAssignedTo(Guid listId, int itemID)
{
SPWeb web = SPContent.Current.Web();
SPList list = web.Lists[listId];
SPListItem item = list.GetItemById(itemID);
item["Assigned To"] = web.CurrentUser;
item.Update();
}
You're going to have to work out how to get this code into to page or web part (SharePoint Designer is not going to cut it I think, you need Visual Studio) but its a starting point.
I have a list with the fields: Title, Client, Project, Description.
There is a view for analysts with the fields visible: Title, Project, Description.
All is fine so far as the analysts work with their views and not with the lists. But when they need to modify the records clicking on Edit, they see and able to modify the 'Client' field too.
How to prevent 'Client' field to be available for editing by the group? is there a way in WSS or I need to look for 3rd party list components?
All fields have a set of properties that determine their visibility in forms, such as "ShowInNewForm", "ShowInEditForm", and "ShowInDisplayForm". There's also some for the file dialog, the list settings page, and a few other places, but that's getting past it. Short answer, yes, you can make the field not show up in the edit form with WSS without needing any 3rd party components.
If you need a field that cannot be seen in the Edit Form by anyone (that is, no one should be able to have it in their form), then you need to modify "ShowInEditForm" to be true. This can't be modified directly through the SharePoint UI, but it is extremely simple using the object model.
If you need certain people to edit it at some point through the SharePoint UI, then you'll instead have to create a custom edit form. That's a bit more complex, so I'll hold off on providing that instruction unless you state you need to go down that route (or someone else passes by this answer and requests it). Nevertheless, it is fully possible with WSS 3.0.
EDIT
If you know already know how to insert inline C# code into an ASPX page, you can perform this very simply using SharePoint Designer. First, follow the instructions from this article, especially make sure you don't delete the default list form web part. Now, in the custom list form you added, make it include every field which anyone will be capable of editing. The last step is to make the form hide those fields for certain people. Let's default them to Visible=false, and flip this switch if the user is allowed them. You can do this either by checking if the current user is part of specified groups, or by checking if the user has a certain permission level only held by people of those groups. You'll basically write some code like the following, I'll use checking for a specified group as the example.
using (SPWeb web = this.Web)
{
SPUser currUser = web.CurrentUser;
string[] listOfGroups = { "Group1Name", "Group2Name", "Group3Name" };
foreach (string groupName in listOfGroups)
{
if (currUser.Groups.Contains(groupName))
{
//Repeat this for each Control, refer to them by their ID. For example, this is for a control with the ID txtTitle.
txtTitle.Visible = true;
}
}
}
If you don't know inline code, you'll have to write a custom ASPX page with a code-behind. Copy EditForm.aspx into a new file - you should do this after setting up a Custom List Form as per the article. You could also build a new ASPX page from scratch, but make sure you include all of the necessary Content placeholders for SharePoint pages. Now, the page currently inherits from Microsoft.SharePoint.WebPartPages.WebPartPage. We need to create custom code that inherits from that class, and change the page to inherit that new custom code instead. In the custom code, override one of the OnLoad or OnInit methods, and include your check for the user's permissions there as detailed earlier. Compile the code, deploy it to your SharePoint server, and it should be functional.
If you want to set fields hidden or display them in new form or edit form page of the list...
Go to the list settings.
In Advanced Settings, enable "Allow management of content types"
By doing so, you will get a List name Link on the List Setting Page.
Open the link and select the fields that you want to hide or uhide using add or remove option.
After saving this, again disable "Allow management of content types" in Advanced Setting...
Thats it :)))
I'm working on a SharePoint publishing site and I want to "log" all the changes made by users in a SharePoint list.
Some searches on the web guided me to the EventReceiver.
But my EventReceiver must be generic and attached to all lists in the site collection. The "log list" has several columns like the name of the list in which the event occurred, the name of the modified item, its old value and its new value.
Can someone guides me on how to achieve this?
There's already a provided answer for you on StackOverflow, hurrayy!!
It sounds possible. Create a class that inherits from SPItemEventReceiver and override ItemUpdating. You can use the following code to get the list:
using (SPWeb web = properties.OpenWeb())
{
SPList list = web.Lists[properties.ListId];
}
You can then use list to grab the list's title and URL. Next, compare each DictionaryEntry entry in properties.AfterProperties to the corresponding value in properties.ListItem to get your differences. Then save it to your log list. The trick would be automatically attaching your Event Receiver to each newly created list. Perhaps a timer job would work.
That said...
Before trying any of that, go to your site collection's Site Settings. Under Site Collection Administration, click Site collection audit settings. Under Specify the Document and Item events to audit, check Editing items. Only go with a custom solution if that does not give you what you need.
Would Version history not achieve the same functionality?
You can see what fields were changed by who and when. Though you would have to look at a list by list basis.
You can also access the version history information via the object model if you want to generate reports web part.
Otherwise using Janis Veinbergs link on how to attach a event handler to all lists and Rich Bennema method of getting the values from the updated item in a generic way, though I would use ItemUpdated as you don’t want to change the data that was updated only copy it to another location so there is no need to catch the data before it is submitted to the SharePoint database
How can I enable the functionality to sync my custom list with Outlook 2007 todo or calendar list? I assume it's possible with custom lists too, but I cannot find any documentation on it.
To my knowledge this is not possible. If you need to sync a todo list, create a task list. Then you can delete all the columns that don't interest you, and add whatever columns you want to use.
The same goes for calendar, if you want a list syncronised with your outlook calendar, then create a calendar list and customize it to your needs.
To expand upon Filip's great answer . . .
According to this MSDN post, the custom list template has a different type designation (100) than the Task Template (106 in the article above, 107 in my research of SP2010). This is what the UI looks at to disable the Outlook Sync button. So, if your custom list is based on a custom content type you created then you can recreate your list to be Outlook compatible.
If your list already contains data, export it to Excel
Create a new list based on the Task template (instead of Custom)
Add your CT and delete the Task CT (if your content type is based on the Task CT i.e. has the columns) and any others your list doesn't need
Add any other columns your list needs but may not be part of your CT (or if you don't use a custom CT)
Use Datasheet view to copy and paste your data into the new list (observe column order)
Caveats: Not all data columns can be copied using this method (e.g. Attachments, system fields, etc.)
Hope this helps clarify
This is available / possible (well it takes some programming to achieve it) - see here.
For my solution, I aggregate data between sites and sync them with outlook. There are some tricky things like to map item's uniqueId to integer ID (probably a database table with mappings) to refer to specific item correctly, but it's not impossible.
But it's not something you can use right away - coding required. However if you really, really need it, then it's a some-way to go.
If your custom list is based off of a sharepoint list, then you can connect it to outlook by generating a link formatted based off the stssync protocol.
I created a custom list definition based off the events (Calendar) list.
It uses the base calendar list template plus some custom fields and forms.
I created a link formatted in accordance with the stssync protocol, and successfully connected it with outlook:
stssync://sts/?ver=1.1&type=calendar&cmd=add-folder&base-url=[site url]&list-url=[your list url]&guid=[GUID of list]&site-name=[SiteName]&list-name=[ListName]
Yeah not possible sadly. Also, if you create custom columns in a task list or calender, Outlook won't sync those columns.
I have been struggling with the same issue and found that it cannot be done with the built in functionality that SharePoint has, but there is a 3rd party program that allows this to be done. You can try with ProperSync. It will allow you to connect the custom fields of a custom list from SharePoint and view and edit them using Outlook.
This is the link to the main site: http://propersync.com/default.aspx
You can override List Ribbon Button, which holds sync logic, and create your custom action on it.
Here is good article about creating ribbons: http://blogs.msdn.com/b/sharepointdeveloperdocs/archive/2009/12/07/sharepointfoundationhowtoaddtabtoribbon.aspx
For List View OutlookSyncButton you should in CommandUIDefinition specify Location="Ribbon.List.Actions.ConnectToClient".
For Calendar View - you should specify Location="Ribbon.Calendar.Calendar.Actions.ConnectToClient".
Now, in CommandUIHandler/CommandAction you specifing JS code that connects to outlook (simply I grab it from SP :)):
alert("Let's go!");
var listid = '{ListId}';
var list;
ExecuteOrDelayUntilScriptLoaded(GetParamsAndSync, 'sp.js');
function GetParamsAndSync()
{
var clientContext = new SP.ClientContext.get_current();
var web = clientContext.get_web();
list = web.get_lists().getById(listid);
clientContext.load(list);
clientContext.load(web);
rf = list.get_rootFolder()
clientContext.load(rf);
clientContext.executeQueryAsync(
function() {
viewUrl=rf.get_serverRelativeUrl();
ExportHailStormOverride('calendar','{SiteUrl}','{ListId}', web.get_title(),list.get_title(),viewUrl,viewUrl,'')
},
function() {alert('Error')});
}
//This function was taken from SharePoint sp.init.js
function ExportHailStormOverride(type,weburl,guid,webname,listname,viewurl,passport,listrooturl,folderurl,folderid)
{ULSA13:;
var strAppName=GetCookie('stsSyncAppName');
var strIconName=GetCookie('stsSyncIconPath');
var maxLinkLength=500;
var maxNameLength=20;
var link='stssync://sts/?ver=1.1'
+'&type='+escapeProperly(type)
+'&cmd=add-folder'
+'&base-url='+escapeForSync(weburl)
+'&list-url='+escapeForSync('/'
+ makeAbsUrl(viewurl).substr(weburl.length+1)+'/')
+'&guid='+escapeProperly(guid);
if (window.self.offlineBtnUser !=undefined)
link+='&user-id='+offlineBtnUser;
var names='&site-name='+escapeForSync(webname)
+'&list-name='+escapeForSync(listname);
var context='';
if (folderurl)
context+='&folder-url='
+ escapeForSync('/'+folderurl.substr(listrooturl.length+1));
if (folderid)
context+='&folder-id='+folderid;
if (link.length+names.length+context.length > maxLinkLength &&
(webname.length > maxNameLength || listname.length > maxNameLength))
{
if (webname.length > maxNameLength)
webname=webname.substring(0, maxNameLength-1)+'...';
if (listname.length > maxNameLength)
listname=listname.substring(0, maxNameLength-1)+'...';
names='&site-name='+escapeForSync(webname)
+'&list-name='+escapeForSync(listname);
}
link=link+names+context;
var L_StssyncTooLong_Text='The name of site or list is too long. Make it shorter.';
if (link.length > maxLinkLength)
alert(L_StssyncTooLong_Text);
else
{
try
{
window.location.href=link;
}
catch (e)
{
alert('Sync error.');
}
}
}