As per docs, kotlin var properties can be bind in ViewModel as
// Kotlin var property
class PersonVarViewModel(person: Person) : ViewModel() {
val name = bind { person.observable(Person::name) }
}
It seems like doesn't work.
How to solve this issue. IDE shows red underline bellow "bind"
but if i write
val name = bind(RoomType::name)
it shows no error. but updating the value using UI fields does'nt update the model value.
Please help
In your class declaration, use var person: Person.
person needs to be a member of the class, not just a parameter to the constructor. You can do this by declaring it var or val in the constructor parameters, or you can add a member field to the class the conventional way and assign it (probably using by property, but not sure if that's what you want)
class PersonVarViewModel(var person: Person) : ViewModel() {
val name = bind { person.observable(Person::name) }
}
For ItemViewModel ...
class PersonVarViewModel(var person: Person) : ItemViewModel<Person>() {
val name = bind { person.observable(Person::name) }
}
You need to make the ItemViewModel aware of the person instance, but also let it react to changes to the underlying item later. You need to assign the person you pass in to the item property of the ItemViewModel. This can be done by passing it in the constructor:
class PersonVarViewModel(person: Person) : ItemViewModel<Person>(person) {
val name = bind(Person::name)
}
Be aware that if you add this constructor, you can only use the that viewmodel with injection if you push it manually into scopes, since it can't be instantiated by the framework. You should therefore either add a noargs constructor as well, or simply omit the person parameter and assign to item after you create it.
If you update the value in the underlying person, it will only be visible in the view model if the value is observable. If not, you have to call rollback() to update changes from the person. You can call rollback for specific fields only.
If possible, use observable properties in your domain model objects to avoid such issues.
Related
When is goto edit data screen apply a model to fill data if user do make some changes but press back button the model saves the data? I am assigning the model to another demo model but it reflects the changed values.
You can create copy method in reference class and assign it's property on back action.
Override your model init method like below.
required override init() {
}
required init(_ model: Person) {
// Assign your Values
}
Use it Like
let obj = People(model : Person)
to copy
Either you can implement copyable protocol in your class model and assigning copy of that model.
or
Create struct instead of class.
Is it possible to pass my subscription ID to a LUIS Dialog, rather than an attribute?
My application has this information on the database, and I need to pass it via a constructor, or another way.
Any sugestions?
Thank you.
The LuisDialog has a constructor that takes a LuisService(s). You can pass in a modelId and subscriptionId, and create the LuisModelAttribute dynamically:
public class LuisTestDialog : LuisDialog<object>
{
public LuisTestDialog(string modelId, string subscriptionId)
: base(new LuisService(new LuisModelAttribute(modelId, subscriptionId)))
{
}
}
The usual way of constraint validating domain objects in Grails is by defining a static constraints closure in the domain object, after which one can call myObject.validate().
Is it possible in some way to pass what should be validated to the validate call and not define a constraints block?
I guess it could be done with Spring validator instances, but is there an easier way where you still have the "goodies" from Grails (max, email, etc.)?
You can pass a list of fields into .validate(["fieldA", "fieldB"]) and it will only validate those fields. You still need a constraints block to define what the constraints are for those fields.
From Grails User Guide:
"The validate method accepts an optional List argument which contains the names of the properties to be validated. When a List of names is specified, only those properties will be validated."
To respond to #eugene82:
#Validateable
class MyDomainValidator {
String email
static constraints = {
email(email:true)
}
}
MyDomain m = new MyDomain()...
MyDomainValidator mv = new MyDomainValidator()..
mv.properties = m.properties
mv.validate()
I imagine such an approach: Create a #Validateable groovy class with static constraints inside with any Grails goodies you need. Let it own all fields like your domain does (e.g. by extending the domain), and provide a way to copy all fields from a domain instance to a new instance of that object, e.g. using a constructor. Than call validate() on that class.
class MyDomain {
String email
MyDomain() {}
MyDomain(email) {
email = this.email
}
}
#Validateable
class MyDomainCustomValidator extends MyDomain {
MyDomainValidator() {}
MyDomainValidator(domain) {
super(domain.email)
}
static constraints = {
email email: true
}
}
def d = new MyDomain('e#mail.com')
new MyDomainCustomValidator(d).validate()
This test is to check that I can return a ViewModel object by creating a customer and calling the Details() controller method.
[TestMethod()]
public void Can_View_AccountDetails()
{
AccountController target = new AccountController(null, null, null, null);
target.customer = new Customer { Id = 4, Active = true, BillingAddress_Id=1, ShippingAddress_Id=2 };
// Act
ActionResult result = target.Details();
// Assert
var resultData = ((ViewResult)result).ViewData.Model as AccountViewModel;
Assert.IsInstanceOfType(resultData, (typeof(AccountViewModel)));
}
'customer' is a member of the controller base class, which is then assigned in Initialize(). Initially I couldn't assign anything to it, but by setting it to 'public' rather than 'protected' I was able to use it in my test and avoided trying to call the base class Initialize() method.
EDIT: 'customer' is populate from a Repository object injected into the base class constructor.
Is this the right way to do this? It seems somehow wrong to change the accessibility level in order to get the test to work.
Also, although I'm trying to use Moq to create my tests, I'm not actually doing any mocking at all here which again, doesn't seem right.
I think your real problem is that the customer information "magically" shows up within the AccountController. The Customer instance should be injected into the AccountController from the outside since it is an external dependency. That being the case you would not have to make the customer property public because you pass it into the AccountController yourself.
Protected means it can only access from derived classes, so the test class would need to inherit the protected class.
Also you stubbed this as being Moq, but i don't see any Mock testing. You should be using interfaces that represent the Customer class so you can Mock the ICustomer interface.
You need to stub your Repository object and set it up so that it returns customer. Then, you don't need to expose .customer property as public (or internal) - you simply tell repository stub to return the one you'd like:
var repositoryStub = new Mock<IRepository>();
var customer = new Customer { /* ... */ };
repositoryStub.Setup(r => r.GetCustomer()).Returns(customer);
And naturally, you need to initialize your AccountContoller with stubbed dependency to repository (and other ones aswell, if needed):
var accountController = new AccountController(repositoryStub, ...);
This of course assumes your AccountController can take repository dependency.
So now, when you call Initialize() on base class, it should use stubbed repository and set your private .customer field to the one you specified it to return during stub setup.
I am implementing ACL security using the spring-security-acl plugin. I have the following domain classes:
package test
class Subitem {
String name
static belongsTo = [employer: Employer]
static constraints = {
name blank: false
}
}
package test
class Employer {
String name
static hasMany = [users: User, items: Subitem]
static belongsTo = User
static constraints = {
name blank: false, unique: true
}
String toString() {
name
}
}
In the create.gsp file which is used to create a Subitem, there is the following statement:
<g:select id="employer" name="employer.id" from="${test.Employer.list()}" optionKey="id" required="" value="${subitemInstance?.employer?.id}" class="many-to-one"/>
From the EmployerController:
def list = {
params.max = Math.min(params.max ? params.int('max') : 10, 100)
[employerInstanceList: employerService.list(params),
employerInstanceTotal: employerService.count()]
}
Following the tutorial given here, I have moved some of the functionality with dealing with Employer to a service called EmployerService:
#PreAuthorize("hasRole('ROLE_USER')")
#PostFilter("hasPermission(filterObject, read)")
List<Employer> list(Map params) {
Employer.list params
}
int count() {
Employer.count()
}
Access to information in any given Employer class instance is restricted using ACL. At present, I can see ALL instances of Employer in the database in the drop down, and I assume that is because I am using the controller list(), not the service list() - however, I only want to see the filtered list of Employer domain classes. However, if I replace the g:select with:
<g:select id="employer" name="employer.id" from="${test.EmployerService.list()}" optionKey="id" required="" value="${subitemInstance?.employer?.id}" class="many-to-one"/>
then I get an internal server error because I haven't passed a Map parameter to the service list() function (and I don't know how to do this within the tag):
URI /security/subitem/create
Class groovy.lang.MissingMethodException
Message No signature of method: static test.EmployerService.list() is applicable for argument types: () values: [] Possible solutions: list(java.util.Map), is(java.lang.Object), wait(), find(), wait(long), get(long)
I only want to see the information that comes from the EmployerService list() function - how do I do this please? How do I reference the correct function from within the gap?
Edit 16 Mar 0835: Thanks #OverZealous, that's really helpful, I hadn't realised that. However, I've tried that and still get the same problem. I've put a println() statement in both the Employer and EmployerService list() functions, and can see that neither actually seems to get called when the g:select tag is parsed (even if I leave the g:select to refer to Employer). Is there another version of the list() function that is being called perhaps? Or how else to get the g:select to take account of the ACL?
Just change your method signature in the Service to look like this:
List<Employer> list(Map params = [:]) {
Employer.list params
}
The change is adding this: = [:]. This provides a default value for params, in this case, an empty map.
(This is a Groovy feature, BTW. You can use it on any method or closure where the arguments are optional, and you want to provide a default.)
OK, I worked it out, and here is the solution to anyone else who comes up against the same problem.
The create Subitem page is rendered by means of the Subitem's create.gsp file and the SubitemController. The trick is to amend the SubitemController create() closure:
class SubitemController {
def employerService
def create() {
// this line was the default supplied method:
// [subitemInstance: new Subitem(params)]
// so replace with the following:
params.max = Math.min(params.max ? params.int('max') : 10, 100)
[subitemInstance: new Subitem(params), employerInstanceList: employerService.list(params),
employerInstanceTotal: employerService.count()]
}
}
So now when the SubitemController is asked by the g:select within the Subitem view for the list of Employers, it calls the EmployerService, which supplies the correct answer. We have simply added 2 further variables that are returned to the view, and which can be referenced anywhere within the view (such as by the g:select tag).
The lesson for me is that the View interacts with the Controller, which can refer to a Service: the Service doesn't play nicely with a View, it seems.