I am creating an app where I want a specific stream to be shown big on another page. There will be one page with all the streams (subscriptions) and one page which will show a SPECIFIC stream on the whole screen.
Send the streamID of a chosen stream to the database.
On the other page, fetch the last added streamID in the database
Get stream by ID and show it on the page
I got the first two steps working, the last step is a problem. I somehow need to fetch a stream object by the given streamId. Is this possible? OR is there another way to achieve this?
I dont know if this is the correct way to do it but you can add all the stream objects in an array:
var streamContainer = [];
session.on("streamCreated", streamCreatedHandler);
streamCreatedHandler = function(e) {
streamContainer.push(e.stream)
}
and when your ID gets fetched unsubscribe from current, iterate over the array and subscribe to the new stream:
for(var i = 0; i < streamContainer.length; i++) {
if(streamContainer[i].id == dbStreamId) {
session.subscribe(streamContainer[i], 'DOMELEMENT', {options});
}
}
You might not even need a database for what you are trying to do. Simply connect both pages (specific stream and all streams) to the same sessionId. You can put streamId in your url as a parameter like this: ?streamId=1343-thneue...
In your streamCreated event, simply check the stream.streamId in your callback function with your url streamId. If they match, then call session.subscribe on that stream object.
Related
I want to define a gRPC endpoint, that when called, returns some initial data and afterwards a stream of data. For example in a game it could create a lobby and return some initial data about the lobby to the creator and afterwards stream an event every time a player joins.
I want to achieve something like this:
message LobbyData{
string id = 1;
}
message PlayerJoin{
string id = 2;
}
service LobbyService {
rpc OpenLobbyAndListenToPlayerJoins(Empty) returns (LobbyData, stream PlayerJoin);
}
Unfortunately this is not possible so I have 2 options:
Option 1 (not what a want)
Creating two seperate RPCs, and call them sequentially on the client:
service LobbyService {
rpc OpenLobby(Empty) returns (LobbyData);
rpc ListenToPlayerJoins(LobbyData) returns (stream PlayerJoin);
}
This however creates the problem that players can join the lobby possibly before the second RPC from the client (ListenToPlayerJoins) reaches the server. So on the server we would need additional logic to open the lobby only after the ListenToPlayerJoins RPC from the creator has arrived.
Option 2 (also not what I want)
Use a single RPC with a sum type:
message LobbyDataOrPlayerJoin{
oneof type {
LobbyData lobby_data = 1;
PlayerJoin player_join = 2;
}
}
service LobbyService {
rpc OpenLobbyAndListenToPlayerJoins(Empty) returns (stream LobbyDataOrPlayerJoin);
}
This would allow for just one RPC, where the first element of the stream is a LobbyData object and all subsequent elements are PlayerJoins. What is not nice about this is that all streamed events after the first one are PlayerJoins but the client receives them still as the sum type LobbyDataOrPlayerJoin. Which is not clean.
Both options seem to me like workarounds. Is there a real solution to this problem?
I am using the FullCalendar jQuery plugin: http://arshaw.com/fullcalendar/
I am also using the example where you can drag external events onto the calendar: http://arshaw.com/js/fullcalendar-1.5.2/demos/external-dragging.html
Right now, I have an event click function as follows:
eventClick: function(event) {
$.ajax({
type: "POST",
url: "ajax-schedule.php",
data: 'id=' + event.id + '&start=' + event.start + '&end=' + event.end,
success: function(data){
alert('done!');
}
});
}
This posts to a file "ajax-schedule.php" where the data is inserted into the mysql database.
I would like to create a link that when clicked will take all of the new/changed events and post the data as shown above, instead of one-by-one.
Something like:
Update Schedule
The "updateSchedule" function would then post all the data.
Looks like the solution may involve the "clientEvents" method: http://arshaw.com/fullcalendar/docs/event_data/clientEvents/
... but I'm sort of lost here.
Any ideas as to how to do this?
You can create an array to store all the events:
var arrayOfEvents = [];
$('#calendar').fullCalendar({
...
drop: function(date) {
...
// retrieve the dropped element's stored Event Object
var originalEventObject = $(this).data('eventObject');
// we need to copy it, so that multiple events don't have a reference to the same object
var copiedEventObject = $.extend({}, originalEventObject);
// Push the event into the array
arrayOfEvents.push(copiedEventObject);
...
},
...
)};
function updateSchedule()
{
var data = "numOfEvents=" + arrayOfEvents.length;
// You can get all events out of the array here
for (var i = 0 ; i < arrayOfEvents.length ; i++) {
var event = arrayOfEvents[i];
data += "&id" + i + "=" + event.id
+ "&start" + i + "=" + event.start
+ "&end" + i + "=" + event.end;
}
// Make your ajax post here
$.ajax({
type: "POST",
url: "ajax-schedule.php",
data: data,
success: function(response){
alert('done!');
}
});
}
So on server-side, your code can get "numOfEvents" and just run a for loop from 0 to numOfEvents to get all events out.
This is something I am planning to implement in future when I get to tweaking performance of my project. My general idea would be something like this:
create handler that stores every change made in fullcalendar, so new events, events updates (drag&drop, resize, title/description/color/whatever is needed), event deletions. I guess the best way would be to create "class" that will be part of fullcalendar itself, tweakable by options of cource, if it wont be part of fc you would need to call it in every state changing function.
This handler stores array of events as well as it provides some basic methods to add fc changes into queue. My idea is to make it event-based, so in array there is member defined by event id which has information about every update made on this event. The way I imagine this to work is not exactly like every event has its own array of updates which server will run sequentially. I think of making this in way, that handler will be set to be saving data every 15/30... seconds (will be set by user) or on user call (pressing button for example). In time between two saves, queue will be populated in way where all updates will be merged into one global change (for example, if you move one event in calendar 5 times, resize 3 times and change title 5 times but at the end its gonna be the very same as it was at the last save, there will be nothing send to server for saving because in reality, no change was made. Or if you do the same and then delete event, its senseless to save all changes and then delete event, instead of that handler will send only delete command as this command is not affected by any other previously done. But if you move event for example two days in future and then 1 day back, it will calculate it was actually moved only by one day forward so there wont be any unnecessary data posted to server).
Eventhought it would be the best to implement it directly to fullCalendar plugin, it also can be standalone class/plugin which could be associated with any kind of application which makes a lot of changes on some set of datas and requires communication to be highly efficient to maximize speed (so user wont be bothered by slow updates/saves). It can be tweaked even more by recognizing exactly which fields (I use fc basically as google calendar, I can change color, desription, title and many more fields, but It would be useless to send whole event as it is if for example only title is changed, no need to send fields that remained the same) in event had been updated and send only those, so there will absolutely no redundant data sent to server. I guess I would do this as every event would have its member in queue array (as I said before) and when new member for event is added to queue, it will store also current event data (which are for comparison only, wont be send to server) for further comparison with next updates (if there will be any).
Hope you didnt get lost and catch my drift. This is just my idea for usefull feature, but I dont see myself working on it this year, depends on school/job. Its not that hard to make it actually, at least not in way I imagine it to be, so there may be someone else who will do it before I even start :)
I'm totally new to Alfresco and their Javascript API so please bear that in mind...
I want to be able to view a list of groups for every user in Alfresco repository.
This is the code I have at the moment:
var gens = search.luceneSearch("TYPE:\"{http://www.alfresco.org/model/content/1.0}person\"");
var logFile = space.childByNamePath("log_user_groups.csv");
if (logFile == null) {
logFile = space.createFile("log_user_groups.csv");
}
logFile.content = "";
for (var i=0; i<gens.length;i++) {
logFile.content += gens[i].properties["cm:userName"]+"\n";
var groupes= people.getContainerGroups(gens[i]);
for (var j=0; j<groupes.length;j++) {
logFile.content += "\t"+groupes[j].properties.shortName +"\t";
logFile.content += "\t"+groupes[j].properties.fullName +"\t";
logFile.content += "\t"+groupes[j].properties.displayName +"\n";
}
}
The file is created with the user name shown correctly. However the group properties 'shortName', 'fullName' and 'displayName' are all null. In fact I printed out all the properties of the 'groupes' object and every field of the object is 'undefined'.
Does any body know what I am doing wrong?
Any help would be greatly appreciated.
Norm.
The easiest way would be to turn it on its head. Instead, for each group ask what groups and what users it contains. At the end, invert it.
You'll want to start with the Root Groups. The groups JS object in Alfresco will give you these, and others. It's implemented by ScriptAuthorityService, so you'll likely want to look at the JavaDocs
First up, get the root groups
var rootGroups = groups.getAllRootGroups() ;
For each group, get all the users in the group (direct and inherited) with getAllUsers(), and store those somewhere. Now, get all the child groups with getChildGroups(). Process each of these in the same way, recursing as needed.
I needed something similar (a complete list of groups) so I did this:
var temp = [];
function addGroups (groups)
{
for each (group in groups)
{
temp.push(group.getDisplayName());
addGroups(group.getChildGroups());
}
}
addGroups(groups.getAllRootGroups());
This works to a point. The problem is that getDisplayName() returns a very non-pretty group name. Normally when dealing with documents and displaying a group name associated with a user I would do people.getContainerGroups() and use group.properties["cm:authorityName"] to get a displayable name (as mentioned above), however the groups I receive from getAllRootGroups() do not have properties (group.properties is undefined).
Does anyone have any idea why the group list returned this way wouldn't have the same properties as those returned by people.getContainerGroups()?
I guess you're using the wrong properties name.
You need the following:
Full Name: groupes[j].properties["usr:authorityName"]
Display Name: groupes[j].properties["usr:authorityDisplayName"]
Short Name: I don't know :) maybe groupes[j].properties["usr:authorityShortName"]
You can also just get the NodeRef id.
Then login to Alfresco explorer. Then go to the administration console --> Node Browser
Paste the id (it should be something like workspace://spacesStore//biglongUUID).There you can see al the properties related to the group.
Or you could just loop the groupes[k].properties map and print all the properties.
My main question here is dealing with the pramas map when having a one-to-many relationship managed within one dynamic form, as well as best practices for dealing with one-to-many when editing/updating a domain object through the dynamic form. The inputs for my questions are as follows.
I have managed to hack away a form that allows me to create the domain objects shown below in one Dynamic form, since there is no point in having a separate form for creating phone numbers and then assigning them to a contact, it makes sense to just create everything in one form in my application. I managed to implement something similar to what I have asked in my Previous Question (thanks for the people who helped out)
class Contact{
String firstName
String lastName
// ....
// some other properties
// ...
static hasMany = [phones:Phone]
static mapping = {
phones sort:"index", cascade: "all-delete-orphan"
}
}
class Phone{
int index
String number
String type
Contact contact
static belongsTo = [contact:Contact]
}
I basically managed to get the values from the 'params' map and parse them on my own and create the domain object and association manually. I.e. i did not use the same logic that is used in the default scaffolding, i.e.
Contact c = new Contact(params)
etc...., i just looped through all the params and hand crafted my domain objects and saved them and everything works out fine.
My controller has code blocks that look like this (this is stripped down, just to show a point)
//create the contact by handpicking params values
def cntct = new Contact()
cntct.firstName = params.firstName
cntct.lastName = params.lastName
//etc...
//get array of values for number,type
def numbers = params['phone.number']
def types = params['phone.type']
//loop through one of the arrays and create the phones
numbers.eachWithIndex(){ num, i ->
//create the phone domain object from
def phone = new Phone()
phone.number = num
phone.type = types[i]
phone.index = i
cntct.addToPhones(phone)
}
//save
My questions are as follows:
What is the best practice of handeling such a situation, would using Command objects work in this case, if yes where can i found more info about this, all the examples I have found during my search deal with one-to-one relationships, I couldn't find an example for one-to-many?
What is the best way to deal with the relatiohsips of the phones in this case, in terms of add/removing phones when editing the contact object. I mean the creation logic is simple since I have to always create new phones on save, but when dealing with updating a contact, the user might have removed a phone and/or editing an exiting one and/or added some new phones. Right now what I do is just delete all the phones a contact has and re-create them according to what was posted by the form, but I feel that's not the best way to do it, I also don't think looping over the existing ones and comparing with the posted values and doing a manual diff is the best way to do it either, is there a best practice on how to deal with this?
Thanks, hopefully the questions are clear.
[edit] Just for more information, phone information can be added and deleted dynamically using javascript (jquery) within the form [/edit]
disclaimer: i do not know if the following approach works when using grails. Let me know later.
See better way for dynamic forms. The author says:
To add LineItems I have some js that calculates the new index and adds that to the DOM. When deleting a LineItem i have to renumber all the indexes and it is what i would like to avoid
So what i do
I have a variable which stores the next index
var nextIndex = 0;
When the page is loaded, i perform a JavaScript function which calculates how many child The collection has and configure nextIndex variable. You can use JQuery or YUI, feel free.
Adding a child statically
I create a variable which store the template (Notice {index})
var child = "<div>"
+= "<div>"
+= "<label>Name</label>"
+= "<input type="text" name=\"childList[{index}].name\"/>"
+= "</div>"
+= "</div>"
When the user click on the Add child button, i replace {index} - by using regex - by the value stored in the nextIndex variable and increment by one. Then i add to the DOM
See also Add and Remove HTML elements dynamically with Javascript
Adding a child dinamically
Here you can see The Paolo Bergantino solution
By removing
But i think it is the issue grow up when deleting. No matter how many child you remove, does not touch on the nextIndex variable. See here
/**
* var nextIndex = 3;
*/
<input type="text" name="childList[0].name"/>
<input type="text" name="childList[1].name"/> // It will be removed
<input type="text" name="childList[2].name"/>
Suppose i remove childList1 What i do ??? Should i renumber all the indexes ???
On the server side i use AutoPopulatingList. Because childList1 has been removed, AutoPopulatingList handles it as null. So on the initialization i do
List<Child> childList = new AutoPopulatingList(new ElementFactory() {
public Object createElement(int index) throws ElementInstantiationException {
/**
* remove any null value added
*/
childList.removeAll(Collections.singletonList(null));
return new Child();
}
});
This way, my collection just contains two child (without any null value) and i do not need to renumber all the indexes on the client side
About adding/removing you can see this link where i show a scenario wich can gives you some insight.
See also Grails UI plugin
Thanks,
Your answer brought some insight for me to do a wider search and I actually found a great post that covers all the inputs in my question. This is just a reference for anyone reading this. I will write a blog entry on how I implemented my case soon, but this link should provide a good source of ino with a working exmaple.
http://www.2paths.com/2009/10/01/one-to-many-relationships-in-grails-forms/
Most of the time I use ajax to manage such problem.
So when the user clicks add new phone I get the template UI from the server for manageability purpose ( the UI just same GSP template that I use to edit, update the phone), so this way you are not mixing your UI with your js code, whenever you want to change the UI you have to deal only with our GSP code.
Then after getting the UI I add it to the page using jquery DOM manipulation. Then after filling the form when they hit add(save) the request is sent to the server via ajax and is persisted immediately.
When the user clicks edit phone the same UI template is loaded from the server filled with existing phone data, then clicking update will update the corresponding phone immediately via ajax, and same thing applies to delete operation.
But one day I got an additional scenario for the use case that says, "until I say save contact no phone shall be saved on the backend, also after adding phones to the contact on the ui if navigate away to another page and come back later to the contact page the phones I added before must be still there." ugh..
To do this I started using the Session, so the above operations I explained will act on the phone list object I stored on the session instead of the DB. This is simple perform all the operation on the phonesInSession but finally dont forget to do this(delete update):
phonesToBeDeleted = phonesInDB - phonesInSession
phonesToBeDeleted.each{
contact.removeFromPhones(it)
it.delete()
}
I know I dont have to put a lot of data in session but this is the only solution I got for my scenario.
If someone has got similar problem/solution please leave a comment.
First, in all your input fields names you add an #:
<input type="text" name="references[#].name"/>
Second, add call a function before submitting:
<g:form action="save" onsubmit="replaceAllWildCardsWithConsecutiveNumbers();">
Third, this is the code for the function that you call before submitting the form:
function replaceAllWildCardsWithConsecutiveNumbers(){
var inputs = $('form').find("[name*='#']");
var names = $.map(inputs, function(el) { return el.name });
var uniqueNames = unique(names);
for (index in uniqueNames) {
var uniqueName = uniqueNames[index];
replaceWildCardsWithConsecutiveNumbers("input", uniqueName);
replaceWildCardsWithConsecutiveNumbers("select", uniqueName);
}
}
function unique(array){
return array.filter(function(el, index, arr) {
return index === arr.indexOf(el);
});
}
function replaceWildCardsWithConsecutiveNumbers(inputName, name){
counter = 0;
$(inputName + "[name='" + name + "']").each(function (i, el) {
var curName = $(this).attr('name');
var newName = curName.replace("#", counter);
$(this).attr('name', newName);
counter += 1;
});
}
Basically, what the code for replaceAllWildCardsWithConsecutiveNumbers() does, is to create a list for all input (or select) elements whose name contains an #. Removes the duplicates. And then iterates over them replacing the # with a number.
This works great if you have a table and you are submitting the values to a command object's list when creating a domain class for the first time. If you are updating I guess you'll have to change the value of counter to something higher.
I hope this helps someone else since I was stuck on this issue for a while myself.
I am using the Exchange Web Services Managed API to work with Tasks (Exchange 2007 SP1). I can create them fine. However, when I try to do updates, it works for all of the fields except for the .Body field. Whenever I try to access (read/update) that field, it gives the following error:
"You must load or assign this property before you can read its value."
The code I am using looks like this:
//impersonate the person whose tasks you want to read
Me.Impersonate(userName); //home-made function to handle impersonation
//build the search filter
Exchange.SearchFilter.SearchFilterCollection filter = New Exchange.SearchFilter.SearchFilterCollection();
filter.Add(New Exchange.SearchFilter.IsEqualTo(Exchange.TaskSchema.Categories, "Sales"));
//do the search
EWS.Task exTask = esb.FindItems(Exchange.WellKnownFolderName.Tasks, filter, New Exchange.ItemView(Integer.MaxValue));
exTask.Subject = txtSubject.Text; //this works fine
exTask.Body = txtBody.Text; //This one gives the error implying that the object isn't loaded
The strange thing is that, inspecting the property bag shows that the object contains 33 properties, but {Body} is not one of them. That property seems to be inherited from the base class .Item, or something.
So, do I need to re-load the object as type Item? Or reload it via .Bind or something? Keep in mind that I need to do this with thousands of items, so efficiency does matter to me.
Calling the Load method solved my problem :)
foreach (Item item in findResults.Items)
{
item.Load();
string subject = item.Subject;
string mailMessage = item.Body;
}
I had the same problem when using the EWS. My Code is requesting the events(Appointments) from the
Outlook calendar, at the end I couldn't reach to the body of the Event itself.
The missing point in my situation was the following "forgive me if there is any typo errors":
After gathering the Appointments, which are also derived from EWS Item Class, I did the following:
1- Create a List with the type Item:
List<Item> items = new List<Item>();
2- Added all appointments to items list:
if(oAppointmentList.Items.Count > 0) // Prevent the exception
{
foreach( Appointment app in oAppointmentList)
{
items.Add(app);
}
}
3- Used the exchanged service "I have already created and used":
oExchangeService.LoadPropertiesForItems(items, PropertySet.FirstClassProperties);
now if you try to use app.Body.Text, it will return it successfully.
Enjoy Coding and Best Luck
I forgot to mention the resource:
http://social.technet.microsoft.com/Forums/en-US/exchangesvrdevelopment/thread/ce1e0527-e2db-490d-817e-83f586fb1b44
He mentioned the use of Linq to save the intermediate step, it will help you avoid using the List items and save some memory!
RockmanX
You can load properties using a custom property set. Some properties are Extended properties instead of FirstClassProperties.
Little example:
_customPropertySet = new PropertySet(BasePropertySet.FirstClassProperties, AppointmentSchema.MyResponseType, AppointmentSchema.IsMeeting, AppointmentSchema.ICalUid);
_customPropertySet.RequestedBodyType = BodyType.Text;
appointment.Load(_customPropertySet);