I try to add a couple of Complications to my App. Most of the Complications needs to be Configurable, so I use an IntentConfiguration for them.
I use this recommendations function to create my complications:
func recommendations() -> [IntentRecommendation<ConfigurationIntent>] {
var recommendations = [IntentRecommendation<ConfigurationIntent>]()
for vehicle in vehicleStatusList {
let intent = ConfigurationIntent()
intent.vehicleItem = VehicleItem(identifier: vehicle.id, display: vehicle.name)
recommendations.append(IntentRecommendation(intent: intent, description: vehicle.name))
}
return recommendations
}
But with this I get the result from the screenshot... How can I change this to get a better User Experience?
When I click one item in the List, I get a correct Complication. But it would be nice to have a change to name them correctly...
I would like to have a list like this:
Yoda (Lock Car)
Yoda (Unlock Car)
Yoda (Open Windows)
Yoda (Close Windows)
The first in the List is a StaticConfiguration...
Related
Basically we might have some data like so
open class RealmCart : RealmObject() {
#PrimaryKey
var _id: String = UUID.randomUUID().toString()
var items: RealmList<RealmCartItem> = RealmList()
var discountCode: String? = null
var userId: String = ""
}
And we do not want people editing these by mistake. We have some failsafe like code owners, labels in the repo, but we also want to have a unit test that can also prevent a merge if the data is changed in any way (add, change, or remove data). Basically, we do not want any accidents, and people are not perfect.
What is the best way to go about such a thing?
This is what I ended up doing:
I created an extension function for my data models
fun RealmObject.testDeclaredFields(): List<String> {
val fields = this::class.java.fields.map { it.name }
return this::class.java.declaredFields
.map { it.name }
.filterNot { fields.contains(it) }
.sorted()
}
Basically this just gets the data model fields, excluding things like companion objects.
Then I was able to create a test simply like
class RealmMessageTest {
#Test
fun `RealmMessage fields match spec`() {
val item = RealmMessage().testDeclaredFields()
assertContentEquals(item, fieldSpec)
}
private val fieldSpec = listOf(
"_id",
"acknowledgeStatusValue",
"body",
"completed",
"createdAt",
"deliveryStatusValue",
"from",
"meta",
"organizationId",
"platforms",
"threadId",
"title"
).sorted()
}
Why do this? Sometimes when someone is making changes carelessly, they will not realize that they have added a field, changed a field, or removed an important field in a data model that is sync'd to the backend. This does not prevent the developer from changing it, but given that they need to now change it in two places, they will be more cognizant whether they need to make this change or not.
I noticed a lot of people questioned why you would need to do this. My answer is that, I work in a very large repo where newer developers edit this without a second thought. This is just to make them more cognizant of changes to these important models, before they break develop. There are code owners for the repo, but they may not always see these changes. It is just an extra precaution.
How about using a mechanism like githooks to prevent the editing of certain files from being committed?
I'm not familiar with githooks, so I can't show you exactly how to do it, but I think it would be good to prevent commits and inform the developer of the situation with an error message.
Today i am facing one issue which has following requirement.
Date should be Editable.
Date should be in particular format.
My Code is like below which is not working.
foreach(var item in Model)
{
<div>#Editable(item, x => x.Start_Date.ToString("MMMM dd,yyyy"))</div>
}
I have tried following approach but throwing "DateParameters" namespace error.
#Editable(item, x=> x.Start_Date, new DateParameters { Format = "MMMM dd,yyyy"})
Also i have learner following thing but how can i achieve this ?
To make a field editable takes two parameters, this has been used to make the Date field editable. The first parameter instructs Glass.Mapper which field to make editable, the second parameter then specifies what the output should be when the page is not in page editing mode. This allows you to control the output of the field when in the two different modes.
Can anybody help me ?
For Experience editor mode, this works for me in razor view:
#Editable(model => model.SomeDateField, new { Format = "dd-MM-yyyy" })
Sitecore 8.2 though, with Glass 4.4.
What you want to do is to provide the default format but keep things the same for the main glass stuff. Like so:
foreach(var item in Model)
{
<div>#Editable(item, x => x.Start_Date, x=>x.Start_Date.ToString("MMMM dd,yyyy"))</div>
}
This will make the date a normal date when editing, but allow you to format it for the final page.
Usually in this case i use different code for "Normal View" and "Experience Editor", so for normal view you need only to display the date with format without making it editable, and on experience editor you need only to edit the date field the author will not care about the date format with experience editor, so your code will be like this :
foreach(var item in Model)
{
{
#if (Sitecore.Context.PageMode.IsExperienceEditorEditing)
{
<div>#Editable(item, x => x.Start_Date)</div>
}
else
{
<div>#item.Start_Date.ToString("MMMM dd,yyyy")</div>
}
}
}
I have tried that as well but it is throwing an error like below
**Value cannot be null. Parameter name: objectToSwitchTo
at Sitecore.Diagnostics.Assert.ArgumentNotNull(Object argument, String argumentName)
at Sitecore.Common.Switcher2.Enter(TValue objectToSwitchTo)
at Glass.Mapper.Sc.GlassHtml.MakeEditable[T](Expression1 field, Expression1 standardOutput, T model, Object parameters, Context context, Database database, TextWriter writer)**
Any help on this ?
As the question states, is there any downside in referencing the service directly in the template as such :
[disabled]="stateService.selectedClient == null || stateService.currentStep == 1"
In my opinion this doesn't seem like good practice and I'd much rather keep a "selectedClient" object in whatever component needs to use it. How can I get the state and store it into local variables, while observing the changes:
example: I want to move from step1 to step2 by changing "currentStep" in the "stateService", however I want the component that keeps "currentStep" ALSO as a local variable to reflect the change in the state?
Is it good practice to reference services in html templates in Angular
2?
I'd generally avoid it. It seems to bring more chaos than good.
Cons:
Coming from OOP background, this approach looks like it breaks the Law of Demeter, but more importantly,
It's no longer MVC, where your controller (Angular2's Component) acts like a mediator between the view and the services.
Like Ced said, what if a call to a service's member is costly and we need to refer to it multiple times in the view?
At the moment my editor of choice (VS Code) does not fully support Angular2 templates; referencing too many things outside of its own Component's scope in a template makes refactoring not fun anymore.
Pros:
Sometimes it looks more elegant (because it saves you 2 lines of code), but trust me, it's not.
How can I get the state and store it into local variables, while
observing the changes
Madhu Ranjan has a good answer to this. I'll just try to make it more complete here for your particular example:
In your StateService, define:
currentStep : Subject<number> = new Subject<number>();
selectedClient: Subject<Client> = new Subject<Client>();
changeStep(nextStep: number){
this.currentStep.next(nextStep);
}
selectClient(client: Client) {
this.selectedClient.next(client);
}
In your Component:
currentStep: number;
constructor(stateService : StateService){
stateService.currentStep.combineLatest(
stateService.selectedClient,
(currStep, client) => {
if (client == null) {
// I'm assuming you are not showing any step here, replace it with your logic
return -1;
}
return currStep;
})
.subscribe(val => {
this.currentStep = val;
});
}
You may try below,
stateService
currentStep : Subject<number> = new Subject<number>();
somestepChangeMethod(){
this.currentStep.next(<set step here to depending on your logic>);
}
component
// use this in template
currentStep: number;
constructor(stateService : stateServiceClass){
stateService.currentStep.subscribe(val => {
this.currentStep = val;
});
}
Hope this helps!!
It is probably not a good idea to expose your subject inside of your state service. Something like this would be better.
StateService
private currentStep: Subject<number> = new Subject<number>();
changeStep(value: number) {
this.currentStep.next(value);
}
get theCurrentStep(): Observable<number> {
this.currentStep.asObservable();
}
Component
currentStep: number;
constructor(private stateService: StateService) {
this.currentStep = this.stateService.theCurrentStep;
}
Template
[disabled]="(currentStep | async) == 1" // Not sure if this part would work
I'm trying to fix the following VBA statement (converting some old code just for fun and to learn Roslyn, not at all looking for anything perfect) to remove the Set keyword so it's a valid VB.NET statement:
Set f = New Foo()
When I look at it through the Syntax Visualizer, I see it turns into trailing trivia.
I'm trying to figure out how to find it using a query. I tried several approaches but all of the following came up empty:
var attempt1 = root.DescendantTokens().Where(t=>t.IsKind(SyntaxKind.SkippedTokensTrivia));
var attempt2 = root.DescendantTokens().Where(t => t.IsKind(SyntaxKind.SetKeyword));
var attempt3 = root.DescendantTrivia().Where(t => t.IsKind(SyntaxKind.SetKeyword));
var attempt4 = root.DescendantNodes()
.OfType<EmptyStatementSyntax>()
.Where(e => e.DescendantTokens().Any(t => t.IsKeyword()));
(Yes, I'm using C# to work with a VisualBasicSyntaxTree)
I can't seem to just find the SetKeyword token that appears in the visualizer, so I thought maybe it's doing some more heavy lifting to piece together what it really is (is that what's meant by structured trivia?). I read something in the documentation that mentioned the compiler can choose to represent it a couple of different ways, so I thought that may be what's going on here.
The query was just the first thing I tried, but in reality I have a SyntaxRewriter I'm using to visit the code to find and fix all such problems (I'm already able to fix missing parentheses around ArgumentLists, for example) but in this case I can't seem to figure out which Visit method to override.
So again, 1) how to query for these from the root and 2) the best override to select from a rewriter. I've been beating my face on the keyboard for two days on this which exponentially increases the likelihood that I'm having a cranio/recto-insertion moment and I need one of you kind souls to pull me out of it.
Cheers!
Brian
Edit: Fixed typo in query attempt1
So it appears that when the compiler reaches an error condition, it will skip all tokens up to the next point where it can recover and continue parsing (the end of the line in this case). The node representing this error condition is an EmptyStatement with trailing syntax trivia containing the rest of the text as parsed tokens.
So if you're going to rewrite a node, you'll want to rewrite EmptyStatements. But you don't want to write just any empty statement, just the ones with the "BC30807" diagnostic code.
public override SyntaxNode VisitEmptyStatement(EmptyStatementSyntax node)
{
var diagnostic = GetLetSetDiagnostic(node);
if (diagnostic == null)
return base.VisitEmptyStatement(node);
return RewriteLetSetStatement(node);
}
private Diagnostic GetLetSetDiagnostic(EmptyStatementSyntax node)
{
//'Let' and 'Set' assignment statements are no longer supported.
const string code = "BC30807";
return node.GetDiagnostics().SingleOrDefault(n => n.Id == code);
}
The implementation of the RewriteLetSetStatement() method is a bit of a mystery to me, I'm not sure how it can be implemented utilizing the compiler services effectively, I don't think that this is a use case that it covers well. The trivia retains the parsed tokens, but there's not much you can do with those tokens AFAIK.
Ideally, we'd just want to ignore the Set token from the tokens and throw it back into the parser to be reparsed. And as far as I can tell, that's not possible, we can only parse from text.
So, I guess the next best thing to do would be to take the text, rewrite it to remove the Set and parse the text again.
private SyntaxNode RewriteLetSetStatement(EmptyStatementSyntax node)
{
var letSetTokens = node.GetTrailingTrivia()
.Where(triv => triv.IsKind(SyntaxKind.SkippedTokensTrivia))
.SelectMany(triv => triv.GetStructure().ChildTokens())
.TakeWhile(tok => new[] {SyntaxKind.LetKeyword, SyntaxKind.SetKeyword}
.Contains(tok.VisualBasicKind()));
var span = new RelativeTextSpan(node.FullSpan);
var newText = node.GetText().WithChanges(
// replacement spans must be relative to the text
letSetTokens.Select(tok => new TextChange(span.GetSpan(tok.Span), ""))
);
return SyntaxFactory.ParseExecutableStatement(newText.ToString());
}
private class RelativeTextSpan(private TextSpan span)
{
public TextSpan GetSpan(TextSpan token)
{
return new TextSpan(token.Start - span.Start, token.Length);
}
}
I want to place some helper functions in another file, since they will be overly reused. I took the Computer-Databse sample's listing file:
https://github.com/playframework/Play20/blob/master/samples/scala/computer-database/app/views/list.scala.html
I created a new file, called "listing.scala.html" under the app/views package, and moved the #link function from the original file to it. This new file looks like this:
#(currentSortBy: String, currentOrder: String, currentFilter: String)
#****************************************
* Helper generating navigation links *
****************************************#
#link(newPage:Int, newSortBy:String) = #{
var sortBy = currentSortBy
var order = currentOrder
if(newSortBy != null) {
sortBy = newSortBy
if(currentSortBy == newSortBy) {
if(currentOrder == "asc") {
order = "desc"
} else {
order = "asc"
}
} else {
order = "asc"
}
}
// Generate the link
routes.Application.listPerfil(newPage, sortBy, order, currentFilter)
}
So, on my original file, I replaced the #link call, with this one:
#title
And the problem is, when I try to compile I get this error:
value link is not a member of play.api.templates.Html
But according to the documentation (http://www.playframework.org/documentation/2.0.4/ScalaTemplateUseCases) it seems to be ok.
Any guess?
Play's templates aren't the best place for placing advanced conditions, most probably you'll get better flexibility by processing it in some controller (or other method) which will return you only required link
ie.:
#title
In your case proposed link(...) function of Application controller can also return a reverse-route.
Keep in mind that including other templates is best option for repeating blocks of HTML but sometimes it's hard to get specified string (mainly because of not trimmed spaces). As you can see there is also problem with calling nested functions. Most probably you can generate whole A tag in the listing.scala.html however using it isn't comfortable enough (IMHO).