How to pass data to the markup of a custom component? - angular7

I have a custom component that allows for editing a user. It displays a dialog which can be fed an existing user. Or not. It has the markup:
<button mat-button (click)="openUserDialog()">Edit</button>
and the controller:
#Component({
selector: 'app-user-edit',
templateUrl: './user-edit.component.html',
})
export class UserEditComponent implements OnChanges {
#Input() existingUser: User;
#Output() userEditedEvent: EventEmitter<User> = new EventEmitter<User>();
userDialogRef: MatDialogRef<UserDialogComponent>;
constructor(
private matDialog: MatDialog,
private userService: UserService
) { }
ngOnChanges() {
}
openUserDialog() {
this.userDialogRef = this.matDialog.open(UserDialogComponent, {
hasBackdrop: false,
data: {
user: this.existingUser
}
});
this.userDialogRef
.afterClosed()
.subscribe(user => {
// TODO validate the edited user
if (user) {
if (this.existingUser) {
user.id = this.existingUser.id;
this.userService.fullUpdate(user)
.subscribe(updatedUser => {
this.userEditedEvent.emit(updatedUser);
// TODO Add a hint that the user has been added
});
} else {
this.userService.add(user)
.subscribe(addedUser => {
this.userEditedEvent.emit(addedUser);
// TODO Add a hint that the user has been updated
});
}
}
});
}
}
The component is then being used in the users list page, once on top of the list to add a new user, with the markup:
<app-user-edit (userEditedEvent)="refreshList($event)"></app-user-edit>
and on each row of the list to edit the user, with the markup:
<app-user-edit [existingUser]="user" (userEditedEvent)="refreshList($event)"></app-user-edit>
The trouble is that the view displays the Edit label both to add and to edit a user.
How could I have a custom Add label on top of the list, and another Update label for each user ?
I feel like I may have overengineered the whole thing.

You can add another #Input parameter say label and pass the value of the label from the mark up.
export class UserEditComponent implements OnChanges {
#Input() existingUser: User;
#Input() label: string = "Edit" // set default to EDIT. If preferred can initialised to empty.
Mark up for ADD:
<app-user-edit (userEditedEvent)="refreshList($event)" label="ADD"></app-user-edit>
Mark up for EDIT:
<app-user-edit [existingUser]="user" (userEditedEvent)="refreshList($event)" label="EDIT"></app-user-edit>
Also, bind parameter label in view where it needs to be shown.

Related

how to select light DOM in angular component

I try to select everything inside the content tag in an angular component
<my-component>
<another-component></another-component>
<another-component></another-component>
<another-component></another-component>
</my-component>
my-component.html
<div>
<content></content>
</div>
my-component.dart
#Component(
selector: "my-component",
templateUrl: 'components/my-component.html',
useShadowDom: false,
publishAs: "ctrl"
)
class MyComponent {
List<Element> content; //elements of content tags
}
How can i select everything inside of and put it into my list.
Is there a special method where i can access the content?
Add a constructor to MyComponent with an argument of type Element and select the children.
class MyComponent {
List<Element> content; //elements of content tags
MyComponent(Element e) {
content = <Element>[].addAll(e.children);
// or
content = <Element>[].addAll((e.querySelector('content') as ContentElement).getDistributedNodes());
}
}
(use with caution, didn't test the code and didn't use Angular.dart for a while)

Unable to Populate select-option tag using g:select in Groovy

I am trying to run the sample Collab-Todo application as in book Beginning Groovy and Grails,page no.123 (Author:Christopher M. Judd,Joseph Faisal Nusairat,and James Shingler Publication:Apress and Edition:2008). Here is my User.groovy file:
package collab.todo
class User {
String userName
String firstName
String lastName
static hasMany = [todos: Todo, categories: Category]
static constraints = {
userName(blank:false,unique:true)
firstName(blank:false)
lastName(blank:false)
}
String toString () {
"$lastName, $firstName"
}
}
The UserController.groovy is as Follows:
package collab.todo
class UserController {
def scaffold = User
def login = {
}
def handleLogin = {
def user = User.findByUserName(params.userName)
if (!user) {
flash.message = "User not found for userName: ${params.userName}"
redirect(action:'login')
}
session.user = user
redirect(controller:'todo')
}
def logout = {
if(session.user) {
session.user = null
redirect(action:'login')
}
}
}
I am able to create,read,update or delete the User table as usual.Here is a sample screenshot of my User view:
In the scaffolding view, I am trying to show the list of all the users in a drop-down(as per the book) using following snippet inside the user/login.gsp:
<g:select name='userName' from="${User?.list()}"
optionKey="userName" optionValue="userName"></g:select>
But what I am getting in the login page is a dropdown with no values populated:
Here is the screenshot of the login page:
In case I change
from="${User?.list()}"
to
from="${User.list()}"
I am getting a NullPointerException. So any clues what is going on?
It looks like the User class could not be found from your view.
Try one of the following:
Add the import statement to your view.
<%# page import="collab.todo.User" %>
Or use the fully qualified name within from attribute.
from="${collab.todo.User.list()}"
The best practice would be to pass the list of users from the controller:
def login = {
[users: User.list()]
}
And use the collection within your view
from="${users}"

Two issues with field validation

I am working on my first ASP.NET MVC 3 project. For some of the fields on an edit page I want the user to be able to either choose a value from previously-entered values or enter a new one, so I'm using the jQuery autocomplete to accomplish this. That part seems to work just fine. Now, for some fields the user can choose to enter a value or not and if they do enter one, I want to validate it against some rules, so I created my own ValidationAttribute.
The validation piece will definitely check the given value against the rules and return the correct boolean value for the IsValid call. Great.
The first problem that I'm having is that if my validator's IsValid returns false, it displays the error message I've specified but if I enter something which is valid, the TextBox clears it's error background color but the error message does not clear. This happens in either FF or IE8.
The second problem is that for FireFox, my autocomplete values will display again when I edit the text in the textbox but in IE 8, once the error condition exists, my autocomplete stops working. Occasionally, if I enter a value which I know is in the autocomplete list, it will show up but it seems a bit flaky.
I may just be doing this validation thing wrong. Here's the relevant code I use. I'd be quite interested in any guidance one can give about either of these issues. The attribute is a test one but it exhibits the behavior on my page.
My ValidationAttribute:
public class MyAttribute : ValidationAttribute
{
...
public override bool IsValid(object value)
{
if (value == null)
{
return true;
}
var stringValue = Convert.ToString(value);
if (stringValue.Length == 0)
{
return true;
}
if (stringValue.Trim().Length == 0)
{
return false;
}
return true;
}
...
}
My autocomplete code:
$("#toppingid").autocomplete({
source: function (request, response) {
$.ajax({
url: '#Url.Action("AvailableToppings", "IceCream")', type: "POST", dataType: "json",
data: { query: request.term },
success: function (data) {
response($.map(data, function (item) {
return { label: item, value: item };
}))
}
})
},
minLength: 1
});
My controller action:
public JsonResult AvailableToppings()
{
// I actually retrieve this differently, but you get the idea
List<string> all = new List<string>() { "BerryCrush", "Caramel", "Fudge" };
return Json(all, JsonRequestBehavior.AllowGet);
}
My view snippet:
#Html.TextBoxFor(model => model.Topping, new { #id = "toppingid" })
#Html.ValidationMessageFor(model => model.Topping)
My viewmodel snippet:
[DisplayName("Topping:")]
[MyAttribute(ErrorMessage = "Can't be all blanks!")]
public string Topping { get; set; }
In my post action, I have logic something like this:
[HttpPost]
public ActionResult Create(IceCreamCreateEditViewModel viewModel)
{
if (ModelState.IsValid)
{
// stuff happens here which isn't germane
return RedirectToAction("Index");
}
// redisplay the view to the user
return Create();
}
I think that's all the relevant pieces of code. Thanks for any guidance you can provide.
Concerning your first question, it looks like the autocomplete plugin removes the input-validation-error class from the textbox when a selection is made. Because of this the textbox clears its background. One way to workaround this is to subscribe for the select event and reapply this class if there is an error (by checking whether the error label is displayed):
$("#toppingid").autocomplete({
source: function (request, response) {
...
},
select: function (event, ui) {
var topping = $('#toppingid');
// find the corresponding error label
var errorLabel = $('span[data-valmsg-for="' + topping.attr('name') + '"]');
if (errorLabel.is(':visible')) {
// if the error label is visible reapply the CSS class
// to the textbox
topping.addClass('input-validation-error');
}
},
minLength: 1
});
As far as your second question is concerned, unfortunately I am unable to reproduce it. The autocomplete doesn't stop working in IE8 if there is a validation error.

Symfony 1.4 : Hide a widget and its validator, based on a cookie?

On my website, I use a ReCaptcha widget in the form used to add comments. Once the form has been correctly sent, I write a cookie to the user's computer.
I would like to remove the ReCaptcha widget when the user has that cookie, so that returning visitors don't have to type a captcha. Can I do that in forms/commentForm.class.php, or do I need to create a new form ?
Save your flag in session:
<?php
...
if ($form->isValid()) {
...
// comment added
$this->getUser()->setAttribute('is_bot', false);
...
}
In another action:
<?php
$this->form = new CommentForm();
if ($this->getUser()->getAttribute('is_bot', true)) {
$this->form->setWidget(); // set captcha widget
$this->form->setValdiator(); // set captcha valdiator
}
Hope this helps.
It is often handy to pass a User instance as an option when creating a form in action:
public function executeNew(sfWebRequest $request)
{
$this->form = new ModelForm(null, array('user'=>$this->getUser));
}
Now you can configure you form based on user session attributes:
class ModelForm extends BaseModelForm
{
public function configure()
{
if ($this->getOption('user')->getAttribute('is_bot', false)
{
//set your widgets and validators
}
}
}

symfony - adding a user to a group (sfGuardUserGroup) in a form

I'm trying to save some users in a custom admin form and I'd like to set them in a particular group, in the sfGuardUserGroup.
So If the user I've just created has an id of 25, then I'd expect an entry in the sfGuardUserGroup table with a user_id of 25 and a group_id of 8 (8 is my group id I want o add these users to.)
Could I do this in the form class, or in the processForm action?
I'm using doctrine and SF1.4
Thanks
This should do what you need:
<?php
class AdminUserForm extends sfGuardUserForm
{
public function configure()
{
//customise form...
}
public function save($con = null)
{
//Do the main save to get an ID
$user = parent::save($con);
//Add the user to the relevant group, for permissions and authentication
if (!$user->hasGroup('admin'))
{
$user->addGroupByName('admin');
$user->save();
}
return $user;
}
}
If you require this behaviour for all sfGuardUser's created you should put this logic in the model for sfGuardUser class. [example below]
// sfGuardUser class
public function save(Doctrine_Connection $conn = null) {
if (!$this->hasGroup('group_name'))
$this->addGroupByName('group_name', $conn);
parent::save($conn);
}
If you require this functionality only on this specific form, you should put the logic within the form. Adding logic to the processForm action would be incorrect as you would be placing business logic within the controller.

Resources