How to clear the typeahead input after a result is selected? - typeahead

I'm using the ng-bootstrap typeahead component to search a customer database. When the user selects a customer from the typeahead results list, I navigate to a customer details page. I've got this working, but I want to clear the input field after navigation has taken place. I've tried setting the model to null or an empty string in the selectItem event logic, but this isn't working:
customer-search-typeahead.component.html
<template #resultTemplate let-r="result" let-t="term">
<div>
<div>
{{r.resource.name[0].given}} {{r.resource.name[0].family}}
</div>
<div>
{{r.resource.birthDate | date: 'dd/MM/yyyy'}}
</div>
</div>
</template>
<input type="text" class="form-control" [resultTemplate]="resultTemplate" (selectItem)="onSelect($event)"
[(ngModel)]="model" placeholder="Start typing a customer name..." [ngbTypeahead]="search"/>
customer-search-typeahead.component.ts
#Component({
selector: 'customer-search-typeahead',
template: require('./customer-search-typeahead.component.html'),
styles: [`.form-control { width: 300px; }`]
})
export class CustomerSearchTypeaheadComponent {
model: any;
searching: boolean;
constructor(private customerService: CustomerService, private router: Router) {}
onSelect($event) {
this.router.navigate(['/customers', $event.item.resource.id]);
this.model = null;
};
search = (text$: Observable<string>) =>
//omitted for brevity
}
The typeahead input looks like this after a selection has been made:
Solution
customer-search-typeahead.component.html
<input type="text" class="form-control" #input [ngbTypeahead]="search" (selectItem)="onSelect($event); input.value='' ">
customer-search-typeahead.component.ts
onSelect($event, input) {
$event.preventDefault();
this.router.navigate(['/customers', $event.item.resource.id]);
};

The issue you witnessing arises from the fact that the NgModel directive is updating model binding asynchronously and the actual model is updated after the onSelect method gets executed. So your model update gets overridden by the NgModel functionality.
Fortunately we (ng-bootstrap authors) got all the flex points in place to cover your use-case :-) There are a couple of things that you could do.
Firstly the $event object passed to the onSelect method has the preventDefault() method and you can call it to veto item selection (and as a result writing back to the model and input field update).
$event.preventDefault() will make sure that the model is not updated and the input field is not updated with the selected item. But text entered by a user will still be part of the input so if you want to clear up this as well you can directly update the input's value property.
Here is code demonstrating all those techniques together:
onSelect($event, input) {
$event.preventDefault();
this.selected.push($event.item);
input.value = '';
}
where input argument is a reference to the input DOM element:
<input type="text" class="form-control" #input
[ngbTypeahead]="search" (selectItem)="onSelect($event, input)">
Finally here is a plunker showing all this in practice: http://plnkr.co/edit/kD5AmZyYEhJO0QQISgbM?p=preview

The above one is template ref value solution.
This is for ngModel solution.
Html code:
<input type="text" class="form-control" [resultTemplate]="resultTemplate" (selectItem)="onSelect($event)"
[(ngModel)]="model" placeholder="Start typing a customer name..." [ngbTypeahead]="search"/>
Component code:
onSelect($event) {
$event.preventDefault();
this.model = null;
this.router.navigate(['/customers', $event.item.resource.id]);
};
$event.preventDefault();
for ngModel value change empty

Related

Livewire checkbox preselected not working

I have collection of permission_types which i can access in my view. I am looping the permission_types to show each one in check box. all the checkboxes are binded to permission_resource, which is defined as a public property array. I want all the checkboxes to be preselected for which i used checked attribute but it won't work, as soon as i remove the wire:model attribute from input all the checkboxes are preselected. which narrows down the problem to wire:model binding.
What i am trying to achieve:
All i want to do is preselect the checkboxes binded to public property $permission_resource. Can anyone please help me out. I really cannot figure out what am i doing wrong here. Appreciate any effort to solve this problem in advance.
Relevent Component Code:
public $permission_types;
public $permission_resource = [];
public function render()
{
$this->permission_types = PermissionType::all();
// dd($this->permission_types->toArray());
return view('livewire.permissions.create-permission-component')
->extends('layouts.app')
->section('content');
}
Relevant View Code:
<div class="row">
#foreach($this->permission_types as $permissionType)
<div class="col-md-3">
<input wire:model="permission_resource" type="checkbox" class="filled-in chk-col-green form-control" id="{{$permissionType['name']}}" value="{{ $permissionType['name'] }}" checked />
<label for="{{ $permissionType['name'] }}" class="p-r-30">{{ ucfirst($permissionType['name']) }} Resource</label>
</div>
#endforeach
</div>
Permission Types Dump
What i have tried so far:
so far i have tried following but none of it worked for me.
1: defining public $permission_resource; instead of public $permission_resource = [];
2: wire:model="permission_resource.{{$permissionType["id"]}}"
3: wire:model="permission_resource.{{$permissionType["name"]}}"
4: wire:model.defer="permission_resource.{{$permissionType["id"]}}"
5: wire:model.defer="permission_resource.{{$permissionType["name"]}}"
6: name="permission_resource.{{$permissionType["id"]}}"
You are binding all the inputs to the same (array) variable, what you want to do is bind each to an element in that array, not to the array itself.
So you would need to prepopulate that array, and then bind each input using $loop->index.
Not sure if you have a good reason for populating permission_types in the render method, better in mount if it is not highly dynamic (likely to change from render to render).
Populating permission_resource in mount might look like this:
public function mount() {
$this->permission_types = PermissionType::all();
$this->permission_resource = $this->permission_types->pluck('name');
}
Then in the blade, bind to elements of the array, and don't set checked yourself, wire:model will always override this anyway, checking your checkbox if the thing you have bound to is truthy, and unchecking if bound var is falsey (this is why everything is unchecked for you with the wire:model binding them to the array, because empty($array) == false, if you just fix the casing of permission_type in the blade you will find the checkbox all come on when you check one, because they are all bound to the same thing).
<input wire:model="permission_resource.{{$loop->index}}" type="checkbox" class="filled-in chk-col-green form-control" id="{{$permission_type['name']}}" value="{{$permission_type['name']}}" />
PS: That will at least get to what you wanted, depending on what you are ultimately trying to do with permission_resource, it may not be a very good/useful representation for the purpose.
try this
public $permission = [];
protected $rules = [
...
'permission' => 'required|array',
];
public function create()
{
if ($this->validate()) {
$data = [
'name' => $this->name,
....
];
$model = Model::create($data);
if (!empty($this->permission)) {
$permissionId = PermissionType::whereIn('id', $this->permission)->pluck('id');
$model->permission()->attach($permissionId); // add name relation instead 'permission' , of create 'attach' of update 'sync'
}
}
}
public function render()
{
return view('livewire.permissions.create-permission-component', [
'permissions' => PermissionType::select('id', 'name')->get()
])
->extends('layouts.app')
->section('content');
}
in View
<div class="row">
#foreach($permissions as $permission)
<div class="col-md-3">
<input wire:model.defer="permission" wire:key="permission{{$permission->id}}" type="checkbox" value="{{$permission->id}}" class="filled-in chk-col-green form-control" />
<label for="{{ $permission->name }}" class="p-r-30">{{ ucfirst($permission->name) }} Resource</label>
</div>
#endforeach
</div>

MVC4 - Creating a List of Model the View and passing to controller

Move MVC blues. I'm trying to populate an empty List in the View and pass it to a controller. Here the model below
//Model
public class Person{
string name {get;set;}
int age {get;set;}
}
Here's the controller that I'd like to send the List to
//Controllers
[HttpPost]
public ActionResult GetPeople(List<Person> people) //Trying to get here
{
foreach(var person in people)
{
//Do Work
}
ActionResult.Redirect(/Somewhere);
}
Here's the initial controller where my view is tied to that creates and passes an empty List
public ActionResult Index()
{
var people = new List<People>();
return View(people);
}
Here's the view. The point of confusion. I somehow need to use a form to add to the List then submit back to GetPeople controller
//Index View
#model List<People> //This starts out empty;
<form method="POST" action="/Home/GetPeople">
<div name="person">
<input name="name" />
<input name="age" />
</div>
<button> Add Another Person</button> //I'm thinking this would create another person div which would be added to the list to be passed to the controller someohow
<button> Submit </button> //Sends List<Person> to GetPeople controller
</form>
Any ideas? Thanks
You need to maintain names of the input fields on your view. To be posted as a member of a list, your fields should look like
<div>
<input name="people[0].name" />
<input name="people[0].age" />
</div>
For the "Add Another Person" button you might need some javascript that will find out current index and insert fields with this index incremented. One thing to watch out is the "Remove" button you might want to have for new entries - make sure it does not creat gaps in indicies.

How to Defer Ember views from synchronously updating from bound input fields

Let's say I have a group of editable users, when one goes to edit that user, ember will synchronously update all views as you type into the bound input text field.
This is cool and all but from an UX point of view it can be misleading.. those values hadn't changed on the server at all.. What I'd like to do is to defer the view update until I set it in the corresponding action method based on a success message from the server.
I have found that when I use {{bind-attr value=firstName}} instead of {{input value=firstName}} that indeed ember no longer updates the view on changing the input field, however the newly typed value is no longer accessible in the actions submit method via this.get('firstName')?
Example.hbs
<script type="text/x-handlebars" id="user">
<h3>Edit {{fullName}}</h3>
<p>
<label>First Name</label>
{{input value=firstName}}
</p>
<p>
<label>Last Name</label>
<input {{bind-attr value=lastName}} />
</p>
<p>
<button {{action 'submit'}}>Submit</button>
</p>
</script>
Example Controller
App.UserController = Ember.ObjectController.extend({
actions: {
submit: function(){
// call to server, on confirmation set 'Globally' first and last names
console.log(this.get('firstName') + " - " + this.get('lastName'));
}
}
});
Here's my jsbin:
http://jsbin.com/jipik/2/edit?html,js,console,output
All you need is a secondary set of variables. Add to your controller a variable named firstNameEdited and set its value initially to firstName. Value bind your input field to this new value and submit this new value to your api call. On a successful return of the API call, update firstName with the value of firstNameEdited.

How do I create a reusable partial for duplicate markup in ember.js?

Given this chunk of HTML:
<div id="email_field" class="control-group">
<label class="control-label" for="account.email">Email</label>
<div id="email_input" class="controls">
<input id="account.email" name="account.email" type="text" placeholder="jpublic#example.com">
<span class="help-block">We just need a valid email address.</span>
</div>
</div>
How do I turn this into a re-usable partial for whatever attribute I want? IE: email, password, password confirmation, etc.
I would assume some sort of view hierarchy but I'm not quite sure.
EDIT: After further exploration I've knocked out {{view}} and {{render}} and figured out exactly what I need:
I want to:
1. Use a specific view (InputView)
2. Use a specific controller (Preferably similarly named: InputController) ({{view}} doesn't do this I think)
3. Be able to use this multiple times ({{render}} can't do this)
4. Be able to pass in values ({{render}} can't do this)
Example:
<!-- templates/application.hbs -->
{{foo "input" name="Email" id="account.email" placeholder="jpublic#email.com"}}
// controllers/input.js
Application.InputController = Ember.ObjectController.extend({
type: "text"
});
// views/input.js
Application.InputView = Ember.View.extend({
templateName: "form/input"
});
<!-- templates/form/input.hbs -->
<input {{bindAttr id="id" name="name" type="type" placeholder="placeholder"}}>
I would create a view that takes all the parameters that are variable. Such as:
{{view App.FormEntity
name="email"
placeholder="My placeholder..."
help="We just need a valid email address."
valueBinding="value"
}}
From there you could extract the label, the various class names, and then use Ember.TextField to bind the value to.
Once you have all of those arguments passed into the view, it should be nice and easy to create the markup using a mixture of bindAttrs, a couple of computed properties, and Ember helpers (such as the Ember.TextField).
I am new to Emberjs and looking for pretty much the same thing, but couldn't you also simply use http://emberjs.com/guides/templates/writing-helpers/ for that?
I will try it myself, so can give more updates if that works out.
Update:
Ok, I got it to work. I created a new Helpers folder with FormgeneratorHelper.js and the following code:
Ember.Handlebars.registerBoundHelper('control-group', function (options) {
var name = options.hash.test.capitalize();
console.log(name);
return new Handlebars.SafeString('<div class="control-group"> \
<label class="control-label" for="input' + name + '">' + name + '</label> \
<div class="controls"> \
<input type="text" id="input' + name + '" placeholder="' + name + '" /> \
</div> \
</div>');
});
An then, no matter in which template you can do:
{{control-group test="email"}}
I really like the idea of using helpers, but if you are using plain Javascript (as opposed to CoffeScript) and have more than one line of code, then it gets a bit ugly unfortunately. But will probably still use that method.
How do I turn this into a re-usable partial for whatever attribute I want? IE: email, password, password confirmation, etc.
What you want is the experimental {{control}} helper. The control helper is currently under development and is considered experimental. To enable it, set ENV.EXPERIMENTAL_CONTROL_HELPER = true before requiring Ember.
I want to:
1. Use a specific view (InputView)
2. Use a specific controller (Preferably similarly named: InputController) ({{view}} doesn't do this I think)
Out-of-box the control helper expects to be passed a template name. That template name is used to lookup a matching view and controller. So for example:
App.InputView = Ember.View.extend()
App.InputController = Ember.Controller.extend()
{{control input}}
See:
A control renders a template with a new instance of the named controller and view
A control's controller and view are lookuped up via template name
Be able to use this multiple times ({{render}} can't do this)
A control can be used multiple times
Be able to pass in values ({{render}} can't do this)
Like the {{view}} helper, {{control}} will accept arbitrary name/value pairs. So as in your example, one could manually pass options to the control helper. Like the {{view}} helper these options become properties on the view instance:
<!-- templates/form/input.hbs -->
<label class="control-label" {{bindAttr for="view.inputId"}}>
{{view.label}}
</label>
<div class="controls">
<input {{bindAttr id="view.inputId" name="view.name" type="type" placeholder="view.placeholder"}}>
<span class="help-block">{{view.help}}</span>
</div>
// controllers/form_input.js
App.FormInputController = Ember.ObjectController.extend({
type: "text"
});
// views/form_input.js
App.FormInputView = Ember.View.extend({
classNames: ["control-group"]
});
<!-- templates/application.hbs -->
{{control "form/input"
inputId="account.email"
name="email"
label="Email"
placeholder="jpublic#email.com"
help="We just need a valid email address."
}}
See this jsbin for working example
Also keep in mind that A control can specify a model to use in its template - with this in place we can bind properties to model data. Also if a controller's model changes, its child controllers are destroyed so the control will reset as expected if the model is swapped out.

Knockout JS Using IF statement and With Statement listen for click event

The input field should be empty on page load.
When the user clicks the 'Edit Post' then I call KO click and 'select' function (all working) .. when I do this call the row selected is bound correctly.
Current code automatically binds on page load so the first record is in the input field.
<div data-bind="with: Selected">
<input type="text" data-bind="value: Name" />
</div>
<i title="Edit Post" data-bind="click: $parent.select"></i>
Example hack
<div data-bind="if **click: $parent.select then** with: Selected">
<input type="text" data-bind="value: Name" />
</div>
<i title="Edit Post" data-bind="click: $parent.select"></i>
How do I write a data-bind if 'click' then do 'with: Select' ?
Update
Add example code: http://jsfiddle.net/uC8Vt/70/
Generally you would just want this to work off of the Selected observable. If it is not populated, then it won't render the area. If it is pooulated, then whatever object that Selected holds will be used.
So, when you call $parent.select you would want to populate Selected with your object.
In fact, observables are functions, so unless you need to run other logic, you can even take a shortcut and bind your click directly against the Selected observable. The current data is passed as the first argument, which sets the value of the observable.
You would change the Selected property depending on the item clicked...
So an example viewModel might be like...
var items = [{ Name: 'item1' }, { Name: 'item2' }];
var viewModel = {
items: items,
Selected: ko.observable(items[0])
}
viewModel.select = function(selectedItem) {
// The first arg is the context of the item clicked
// Selected in an observable
viewModel.Selected(selectedItem);
};
Then, as Selected changes... your Name binding will automatically update.