AndroidViewModel updating MutableLiveData object - android-room

I am having a problem initializing a boolean property in my ViewModel. I am not sure the right way to go about this.
I have a Switch control on the main activity, and if I change the switch I want to change the boolean startsWith value. Depending on the boolean value I will call the corresponding Dao function.
I am trying to initialize the value, but not sure how to do this. Should I observe the boolean value, should I use two way binding, should this property be MutableLiveData?
wordListViewModel = ViewModelProviders.of(this).get(WordListViewModel.class);
wordListViewModel.setStartsWith(true);
I get this error, cannot even start Activity:
Attempt to invoke virtual method 'boolean java.lang.Boolean.booleanValue()' on a null object reference
Code:
public class WordListViewModel extends AndroidViewModel {
final MutableLiveData<String> searchText = new MutableLiveData<>();
final MutableLiveData<Boolean> startsWith = new MutableLiveData<>();
private final LiveData<List<WordEntity>> list;
private AppDatabase appDatabase;
public WordListViewModel(Application application) {
super(application);
appDatabase = AppDatabase.getDatabase(this.getApplication());
if (startsWith.getValue() == true)
list = Transformations.switchMap(searchText, searchText -> {
return appDatabase.wordDao().getWordsStartingWith(searchText);
});
else
list = Transformations.switchMap(searchText, searchText -> {
return appDatabase.wordDao().getWordsLike(searchText);
});
}

I think I figured it out. The check has to be inside the switchMap function.
The rest of the code only runs when the model is initialized.
I changed my code and it worked:
if (startsWith.getValue() == null)
startsWith.setValue(true);
list = Transformations.switchMap(searchText, searchText -> {
if (startsWith.getValue() == true)
return appDatabase.dictWordDao().getWordsStartingWith(searchText);
else
return appDatabase.dictWordDao().getWordsLike(searchText);
});

Related

Vaadin Select - fields changed inside binder's apply do not write changes to bean from item

Using Vaadin 14.7.0.
Inside a CRUD editor (Enhanced CRUD Editor) I'm building various fields, amongst which I have a Select.
The Select is initialized with a list of options but I'm also trying to change the items from CRUD form edit to CRUD form edit depending on changes from my underlying database so that the user can select new values.
BindingBuilder<Item, SelectOption> bindingBuilder = binder.forField(s);
if (prop.isMandatory()) {
bindingBuilder.asRequired(requiredI18n);
}
bindingBuilder.bind(new ValueProvider<Item, SelectOption>() {
private static final long serialVersionUID = 1L;
#Override
public SelectOption apply(final Item item) {
ListPropertyDefinition lp = ((ListPropertyDefinition)prop);
Serializable currentValue = item.get(lp.getName());
Collection<SelectOption> sOptions = null;
if (lp.getSelectOptions() != null) {
ListDataProvider<SelectOption> ldp = (ListDataProvider)s.getDataProvider();
sOptions = ldp.getItems();
} else {
sOptions = getNewOptions(item, prop.getName());
s.setItems(sOptions);
}
return new SelectOption("N/A", currentValue);
}
}, new Setter<Item, SelectOption>() {
private static final long serialVersionUID = 1L;
#Override
public void accept(final Item bean, final SelectOption fieldvalue) {
bean.set(prop.getName(), fieldvalue != null ? fieldvalue.getValue() : null);
}
});
Now, if the s.setItems(sOptions) branch is being called then the Select field gets populated with the new values sent by the backend but when I'm saving the item the value that I get is null, regardless of what I select in the select field.
This does not happen when I do not change the items in the select field (i.e. if branch).
I did some debugging for comparing 2 select fields - one that changes its values on the fly and one that has values that don't change... from what I could see the field that has values changing on the fly has a null buffered value as seen in the attached image:
vs the field that does not have its values modified in the binder's apply method:
Not sure if what I'm doing is the right way of "refreshing" a select field's values and / or what should I do so that I get the selected value back in the bean on CRUD form save.
I think you are doing things in overly complicated manner. Based on your code I think your principal challenge is how to set empty selection to be "N/A"
For that you simply need to enable empty selection to be allowed. You need to have one placeholder item for empty selection, for which you generate "N/A" as caption. Then you can just do:
Binder<Item> binder = new Binder<>();
Select<SelectOption> select = new Select<>();
...
select.setEmptySelectionAllowed(true);
select.setEmptySelectionCaption("N/A");
binder.forField(s).bind(Item::getProperty,Item::setProperty);
public class SelectOption {
...
}
// Make the item bean also to follow POJO convention
public class Item {
private SelectOption property;
public SelectOption getProperty() {
return property;
}
public void setProperty(SelectOption property) {
this.property = property;
}
}

grails databinding param a mapping on b

in my current project, i was so stupid to make an API which expects the variable private. in the controller it gets mapped to isPrivate, but now i wanted to make a commandObject (#validatable) to check if everything is valid. How can i map the private variable using autobinding on isPrivate?
#Validateable
class EventCommand{
boolean isPrivate
boolean fullDay
String title
String location
String description
static constraints = {
location(nullable: true)
description(nullable: true)
fullDay (nullable: false)
isPrivate(nullable: false)
title (blank: true, nullable: false)
}
}
and the code where the databinding happens (inside a grails controllor):
def add() {
def jsonData = request.JSON
EventCommand command = new EventCommand(jsonData)
if(!command.validate()){
throw new QuivrException(command)
}
boolean isPrivate = jsonData.private
//some things happen, uninmportant
}
i already tried using the #BindUsing annotation, but i always keep getting the error that EventCommand has no property named "private" (the matches works, but he tries to match private to something none-existant)
is there any way to solve this without changing the received private to isPrivated (already got old versions of the application and got 20% not on latest version)
Well from your jsonData remove the private property and then do the binding and after binding add the private manually from a variable in which you should be getting the private value.
Hence your add could be something like
def add() {
def jsonData = request.JSON
String isPrivate = jsonData.private
jsonData.remove("private")
EventCommand command = new EventCommand(jsonData)
if(!command.validate()){
throw new QuivrException(command)
}
command.isPrivate = isPrivate as Boolean
}

Get PropertyInfo from multiple property objects found in an Expression object

I need to change a function that accepts one Expression with one property inside and give it the ability to work with 2 properties at least.
I have the following base class that contains nested ElementHelper class
public class DomainObjectViewModel<TModel> where TModel : DomainObject
{
public class ElementHelper
{
public static void Create<T1>(TModel model, Expression<Func<TModel, T1>> expression)
{
var getPropertyInfo = GetPropertyInfo(expression);
//Do cool stuff
}
private static PropertyInfo GetPropertyInfo<T1>(Expression<Func<TModel, T1>> propertyExpression)
{
return (PropertyInfo)((MemberExpression)propertyExpression.Body).Member;
}
}
}
-ElementHelper class contains a Create function that gets the propertyInfo of the expression and only works if you pass one property in the expression.
Then I have the following inherited class that uses the helper function in the constructor.
public class ProductViewModel : DomainObjectViewModel<ProductEditViewModel>
{
public ProductViewModel(ProductEditViewModel model)
{
//It works for one property in the Expression
ElementHelper.Create(model, x => x.LaunchDate);
//Give the ability to pass multiple paramenters in the expression
ElementHelper.Create(model, x => new { x.LaunchDate, x.ApplyLaunchDateChanges });
}
}
I think I can use NewExpression (new { x.LaunchDate, x.ApplyLaunchDateChanges }) in order to pass it a collection of properties, but I cannot make it work.
Would you use same approach?
How you can split the passed Expression so you can get the propertyinfo of each properties found in the NewExpression object?
Well, since ElementHelper.GetPropertyInfo is your own method, you can decide what is allowed to pass, and then handle it appropriately inside that method.
Currently you handle only MemberExpression, so that's why it works only with single property accessor. If you want to be able to pass new { ... }, you need to add support for NewExpression like this:
private static IEnumerable<PropertyInfo> GetPropertyInfo<T1>(Expression<Func<TModel, T1>> propertyExpression)
{
var memberExpression = propertyExpression.Body as MemberExpression;
if (memberExpression != null)
return Enumerable.Repeat((PropertyInfo)memberExpression.Member, 1);
var newExpression = propertyExpression.Body as NewExpression;
if (newExpression != null)
return newExpression.Arguments.Select(item => (PropertyInfo)((MemberExpression)item).Member);
return Enumerable.Empty<PropertyInfo>(); // or throw exception
}

Programmatically determine content item type in Orchard without magic strings

I am implementing a custom module in Orchard to track the number of views for each content item. In my handler, I am checking to see if the content item's type is the default Orchard "Page" type, but right now it is using the Equals function and magic strings. Here's my code:
public class ContentItemViewRecordHandler : ContentHandler
{
private readonly IOrchardServices services;
private readonly IRepository<ContentItemViewRecord> repository;
public ContentItemViewRecordHandler(IOrchardServices services, IRepository<ContentItemViewRecord> repository)
{
this.services = services;
this.repository = repository;
OnGetDisplayShape<CommonPart>(RecordView);
}
private void RecordView(BuildDisplayContext context, CommonPart part)
{
var contentItemType = context.ContentItem.ContentType;
// THIS IS THE IF STATEMENT IN QUESTION
if (!contentItemType.Equals("Page", StringComparison.CurrentCultureIgnoreCase))
{
return;
}
var contentItemViewRecord = new ContentItemViewRecord
{
ContentItemRecordId = context.ContentItem.Id,
Username = services.WorkContext.CurrentUser.UserName,
HostAddress = services.WorkContext.HttpContext.Request.UserHostAddress,
DateCreated = DateTime.UtcNow
};
repository.Create(contentItemViewRecord);
}
}
Anyone know if there is a way to determine the content item's type without the magic strings?
Content types are not .NET types. They are dynamic entities that only exist at runtime. Strings are therefore perfectly fine to identify them.

LINQ-To-Sharepoint Multiple content types for a single list

I'm using SPMetal in order to generate entity classes for my sharepoint site and I'm not exactly sure what the best practice is to use when there are multiple content types for a single list. For instance I have a task list that contains 2 content types and I'm defining them via the config file for SPMetal. Here is my definition...
<List Member="Tasks" Name="Tasks">
<ContentType Class="LegalReview" Name="LegalReviewContent"/>
<ContentType Class="Approval" Name="ApprovalContent"/>
</List>
This seems to work pretty well in that the generated objects do inherit from WorkflowTask but the generated type for the data context is a List of WorkflowTask. So when I do a query I get back a WorkflowTask object instead of a LegalReview or Approval object. How do I make it return an object of the correct type?
[Microsoft.SharePoint.Linq.ListAttribute(Name="Tasks")]
public Microsoft.SharePoint.Linq.EntityList<WorkflowTask> Tasks {
get {
return this.GetList<WorkflowTask>("Tasks");
}
}
UPDATE
Thanks for getting back to me. I'm not sure how I recreate the type based on the SPListItem and would appreciate any feedback.
ContractManagementDataContext context = new ContractManagementDataContext(_url);
WorkflowTask task = context.Tasks.FirstOrDefault(t => t.Id ==5);
Approval a = new Approval(task.item);
public partial class Approval{
public Approval(SPListItem item){
//Set all properties here for workflowtask and approval type?
//Wouldn't there be issues since it isn't attached to the datacontext?
}
public String SomeProperty{
get{ //get from list item};
set{ //set to list item};
}
Linq2SharePoint will always return an object of the first common base ContentType for all the ContentTypes in the list. This is not only because a base type of some description must be used to combine the different ContentTypes in code but also it will then only map the fields that should definitely exist on all ContentTypes in the list. It is however possible to get access to the underlying SPListItem returned by L2SP and thus from that determine the ContentType and down cast the item.
As part of a custom repository layer that is generated from T4 templates we have a partial addition to the Item class generated by SPMetal which implements ICustomMapping to get the data not usually available on the L2SP entities. A simplified version is below which just gets the ContentType and ModifiedDate to show the methodology; though the full class we use also maps Modified By, Created Date/By, Attachments, Version, Path etc, the principle is the same for all.
public partial class Item : ICustomMapping
{
private SPListItem _SPListItem;
public SPListItem SPListItem
{
get { return _SPListItem; }
set { _SPListItem = value; }
}
public string ContentTypeId { get; internal set; }
public DateTime Modified { get; internal set; }
public virtual void MapFrom(object listItem)
{
SPListItem item = (SPListItem)listItem;
this.SPListItem = item;
this.ContentTypeId = item.ContentTypeId.ToString();
this.Modified = (DateTime)item["Modified"];
}
public virtual void MapTo(object listItem)
{
SPListItem item = (SPListItem)listItem;
item["Modified"] = this.Modified == DateTime.MinValue ? this.Modified = DateTime.Now : this.Modified;
}
public virtual void Resolve(RefreshMode mode, object originalListItem, object databaseObject)
{
SPListItem originalItem = (SPListItem)originalListItem;
SPListItem databaseItem = (SPListItem)databaseObject;
DateTime originalModifiedValue = (DateTime)originalItem["Modified"];
DateTime dbModifiedValue = (DateTime)databaseItem["Modified"];
string originalContentTypeIdValue = originalItem.ContentTypeId.ToString();
string dbContentTypeIdValue = databaseItem.ContentTypeId.ToString();
switch(mode)
{
case RefreshMode.OverwriteCurrentValues:
this.Modified = dbModifiedValue;
this.ContentTypeId = dbContentTypeIdValue;
break;
case RefreshMode.KeepCurrentValues:
databaseItem["Modified"] = this.Modified;
break;
case RefreshMode.KeepChanges:
if (this.Modified != originalModifiedValue)
{
databaseItem["Modified"] = this.Modified;
}
else if (this.Modified == originalModifiedValue && this.Modified != dbModifiedValue)
{
this.Modified = dbModifiedValue;
}
if (this.ContentTypeId != originalContentTypeIdValue)
{
throw new InvalidOperationException("You cannot change the ContentTypeId directly");
}
else if (this.ContentTypeId == originalContentTypeIdValue && this.ContentTypeId != dbContentTypeIdValue)
{
this.ContentTypeId = dbContentTypeIdValue;
}
break;
}
}
}
Once you have the ContentType and the underlying SPListItem available on your L2SP entity it is simply a matter of writing a method which returns an instance of the derived ContentType entity from a combination of the values of the base type and the extra data for the missing fields from the SPListItem.
UPDATE: I don't actually have an example converter class as we don't use the above mapping extension to Item in this way. However I could imagine something like this would work:
public static class EntityConverter
{
public static Approval ToApproval(WorkflowTask wft)
{
Approval a = new Approval();
a.SomePropertyOnWorkflowTask = wft.SomePropertyOnWorkflowTask;
a.SomePropertyOnApproval = wft.SPListItem["field-name"];
return a;
}
}
Or you could put a method on a partial instance of WorkflowTask to return an Approval object.
public partial class WorkflowTask
{
public Approval ToApproval()
{
Approval a = new Approval();
a.SomePropertyOnWorkflowTask = this.SomePropertyOnWorkflowTask;
a.SomePropertyOnApproval = this.SPListItem["field-name"];
return a;
}
public LegalReview ToLegalReview()
{
// Create and return LegalReview as for Approval
}
}
In either situation you would need to determine the method to call to get the derived type from the ContentTypeId property of the WorkflowTask. This is the sort of code I would normally want to generate in one form or another as it will be pretty repetitive but that is a bit off-topic.

Resources