As our page numbers grow I'm starting to run into difficulties preventing duplicate frames, especially when using the side drawer. If I navigate A -> B -> A, I will end up with 3 instances, 2 of A and 1 of B. This means I have to somehow decided whether the navigation is a real navigation or a "backToPreviousPage".
Ideally I should just be able to put a route in and it would intelligently decide what to do, e.g:
router.navigate(['A'])
router.navigate(['B'])
router.navigate(['A'])
Should equal A - navigate -> B - backToPreviousPage -> A
Right now, my plan is to make a service to record the last route that was navigated to. That way I can just do myService.navigate() and it will automatically decide if it should do a real navigation or use routerExtensions.backToPreviousPage() based on if the current route matches the previous.
Before I do that though, I want to make sure there isn't some glaring obvious way I should be handling this. This kind of seems like a dirty way to do it. To me it seems like the Nativescript router should handle this by default, but I've already confirmed that my A -> B -> A scenario re-runs the ngOnInit, and I haven't seen any options that could make this happen.
The page router outlet should keep track of what is there in stack / history. Based on url segments you could decide whether you want to navigate back or navigate to new component.
constructor(pageRouterOutlet: PageRouterOutlet) {
// `outlet` is private
(<any>pageRouterOutlet).outlet.states.forEach((state) => {
console.log(state.segmentGroup);
});
}
In SugarCRM 7.9 how we can change the maximum number of records to be displayed in a specific subpanel.
In Developer guide i have found that by changing the 'list_max_entries_per_subpanel' limit in config override we can change the records display limit for all subpanels but i want to have the effect only in my specific subpanel for example Contacts subpanel available in Accounts module.
I was interested to find out the answer to this too, so I did some digging and figured this out. As per your example of displaying a different number in the Contacts subpanel in Accounts, here's what you can do:
Add the following file to custom/modules/Contacts/clients/base/views/subpanel-list/subpanel-list.js
({
extendsFrom: "SubpanelListView",
initialize: function(options){
this._super("initialize", [options]);
if (this.context.get("parentModule") == "Accounts"){
this.context.set("limit",1);
}
}
})
If you'd like to know more specifically what's going on, I'll elaborate. Here's a breakdown of what's happening:
State that you're extending the standard subpanel list view.
Override the parent class' initialize function.
Call the parent initialize function (to ensure all superclass behaviour is respected)
If this (Contacts) subpanel has a parent module of Accounts (i.e. this subpanel is one of the ones displayed below the Accounts record view), then set the context property "limit" to the desired value.
I've tested this successfully by linking 3 contacts to an Account, and it only displayed 1, and subsequently linked 3 contacts to an Opportunity, and it showed all 3.
I have an asset X with 4 properties xp1, xp2, xp3, xp4.
I have 2 participants P1 & P2.
I would like Participant P1 to read only xp1 & xp3 properties whereas participant p2 can read/write xp2 property.
How do I write access control rule for this?
As per documentation, we can write rules at the Object level but not at the property.
How can this be achieved?
as per Rocketchat -> https://chat.hyperledger.org/channel/composer?msg=72gQcE9WBGig5YiBL #praveencastelino currently not possible for property (field) based access control in ACL runtime -> https://github.com/hyperledger/composer/issues/983 which you've commented on and something that is in plan.
A workaround might be to have two assets that are --> relationships to the parent asset X (each new asset has eacn of xp1/xp2 or xp3/xp4) and then P1 or P2 as appropriate would have READ access to that data only, in your ACL rules.
I develop the system where I assume will be many users. Each user has a profile represented inside the application as a record. To store user's profile I do the following base64:encode_to_string(term_to_binary(Profile)), so basically profiles stored in serialized maner.
So far everything is just fine. Now comes the question:
From time to time I do plan to extend profile functionality by adding and removing certain fields in it. My question is what is a best strategy to handle these changes in the code?
The approach I see at the moment is to do something like this:
Profile = get_profile(UserName),
case is_record(Profile, #profile1) of
true ->
% do stuff with Profile#profile1
ok;
_ ->
next
end,
case is_record(Profile, #profile2) of
true ->
% do stuff with Profile#profile2
ok;
_ ->
next
end,
I want to know if there are any better solutions for my task?
Additional info: I use is simple KV storage. It cannot store Erlang types this is why I use State#state.player#player.chips#chips.br
Perhaps, you could use proplists.
Assume, you have stored some user profile.
User = [{name,"John"},{surname,"Dow"}].
store_profile(User).
Then, after a couple of years you decided to extend user profile with user's age.
User = [{name,"John"},{surname,"Dow"},{age,23}].
store_profile(User).
Now you need to get a user profile from DB
get_val(Key,Profile) ->
V = lists:keyfind(Key,1,Profile),
case V of
{_,Val} -> Val;
_ -> undefined
end.
User = get_profile().
UserName = get_val(name,User).
UserAge = get_val(age,User).
If you get a user profile of 'version 2', you will get an actual age (23 in this particular case).
If you get a user profile of 'version 1' ('old' one), you will get 'undefined' as an age, - and then you can update the profile and store it with the new value, so it will be 'new version' entity.
So, no version conflict.
Probably, this is not the best way to do, but it might be a solution in some case.
It strongly depend of proportion of number of records, frequency of changes and acceptable outage. I would prefer upgrade of profiles to newest version first due maintainability. You also can make system which will upgrade on-fly as mnesia does. And finally there is possibility keep code for all versions which I would definitely not prefer. It is maintenance nightmare.
Anyway when is_record/2 is allowed in guards I would prefer
case Profile of
X when is_record(X, profile1) ->
% do stuff with Profile#profile1
ok;
X when is_record(X, profile2) ->
% do stuff with Profile#profile2
ok
end
Notice there is not catch all clause because what you would do with unknown record type? It is error so fail fast!
You have many other options e.g. hack like:
case element(1,Profile) of
profile1 ->
% do stuff with Profile#profile1
ok;
profile2 ->
% do stuff with Profile#profile2
ok
end
or something like
{_, F} = lists:keyfind({element(1,Profile), size(Profile)},
[{{profile1, record_info(size, profile1)}, fun foo:bar/1},
{{profile2, record_info(size, profile2)}, fun foo:baz/1}]),
F(Profile).
and many other possibilities.
The best approach is to have the copy of the serialized (profile) and also a copy of the same but in record form. Then , each time changes are made to the record-form profile, changes are also made to the serialized profile of the same user ATOMICALLY (within the same transaction!). The code that modifies the users record profile, should always recompute the new serialized form which, to you, is the external representation of the users record-record(record_prof,{name,age,sex}).
-record(myuser,{
username,
record_profile = #record_prof{},
serialized_profile
}).
change_profile(Username,age,NewValue)->
%% transaction starts here....
[MyUser] = mnesia:read({myuser,Username}),
Rec = MyUser#myuser.record_profile,
NewRec = Rec#record_prof{age = NewValue},
NewSerialised = serialise_profile(NewRec),
NewUser = MyUser#myuser{
record_profile = NewRec,
serialized_profile = NewSerialised
},
write_back(NewUser),
%% transaction ends here.....
ok.
So whatever the serialize function is doing, that's that. But this always leaves an overhead free profile change. We thereby keep the serialized profile as always the correct representation of the record profile at all times. When changes occur to the record profile, the serialized form must also be recomputed (transactional) so as to have integrity.
You could use some extensible data serialization format such as JSON or Google Protocol Buffers.
Both of these formats support adding new fields without breaking backwards compatibility. By using them you won't need to introduce explicit versioning to your serialized data structures.
Choosing between the two formats depends on your use case. For instance, using Protocol Buffers is more reliable, whereas JSON is easier to get started with.
So imagine I'm building a Multi User Dungeon system using a MVC web application. To describe the areas the player can explore, the system can contain a number of Maps, which will consist of Rooms and Doors - where doors connect two Rooms.
Consider the authoring part of the system. To create a Map is easy - I need URLs like:
/Author/Maps (an index of my maps)
/Author/Maps/Create (a new Map)
/Author/Maps/Detail/3 (show Map details)
/Author/Maps/Edit/3 (edit map details)
Using a Routing scheme: /Author/{controller}/{action}/{ID}
It's the URLs for the Rooms that I need help with. When creating a new Room, I need to know which Map I'm creating it for.
/Author/Rooms/CreateIn/[mapID] ?
And then for editing a room's details:
/Author/Rooms/Edit/[roomID]
/Author/Rooms/Detail/[roomID]
Would this routing scheme work? And should the view that lists all the Rooms for a Map be an "Index" action on the Rooms controller, with a MapID passed in, or a "Rooms" action on a Map controller?
Thanks.
I don't know if this is best practice, but I would do it like this:
Add a new route: /Author/Maps/{mapID}/Rooms/{action}/{roomID}
Since this is a route that I would only expect to use for the RoomsController, I wouldn't have a {controller} parameter in that route. Just set the controller to "Rooms" in the route's default object.
Then all the actions in your RoomsController would know which map they're working with.
The default Index action for RoomsController could be a list of all the Rooms for the specified map.
The Create action would look like Create(int mapID) and the Details action would look like Details(int mapID, int roomID)
Edit: regarding invalid URLs with a mismatched mapID and roomID, you could just ignore the mapID, but I think the better process would be to validate that the specified mapID is correct and show an error message if it is not.
Edit 2: (additional thoughts regarding the relationship between mapID and roomID)
You could just make roomID unique within the given map. Therefore, map 5, room 3 would be a different room than map 8, room 3.