Laravel Backpack javascript dynamic change of select option - laravel-backpack

I am running laravel backpack 3.4 and created a custom select2 fieldtype from the standard one, I am now trying to based on an onchange event change the value selected on another select options but no change is happening
This is the field declararion
<select onchange="updateunit(this, '{{$field['name']}}' )" id="{{$field['name']}}_<% $index %>" data-index="<% $index %>"
ng-model="item.{{ $field['name'] }}"
[ngValue]="value"
#include('crud::inc.field_attributes', ['default_class' => 'form-control select2'])
>
<option value="">-</option>
#if (isset($field['model']))
#foreach ($field['model']::all() as $connected_entity_entry)
<option value="{{ $connected_entity_entry->getKey() }}"
>{{ $connected_entity_entry->{$field['attribute']} }}</option>
#endforeach
#endif
</select>
And this is the way I am trying to modify the select field selected option
function updateunit(object,name){
var fieldname;
fieldname = object.id;
fieldname = fieldname.replace('product_id','order_unit');
/* data:'_token = <?php echo csrf_token() ?>', */
$.ajax({
type:'POST',
url:'/getmsg',
data: {id:object.value},
async: false,
success:function(data) {
alert(fieldname);
alert(data.msg);
document.getElementById(fieldname).value = data.msg;
},
error:function(){alert('Unidade de Compra não está definida')},
});
This is not working, but I have not enough knowledge either on JS neither Angular to understand why this won't bind.

The elements that are created by your field configurations use the jquery select2 plugin to create a fancy select box. It does this by hiding the plain select element then displaying an html structure that builds the fancy dropdown etc in its place.
document.getElementById(fieldname).value = data.msg; will set the value of the hidden select field, but will not update the value shown by the plugin's fancy html dropdown.
To make the value that's display by the plugin change, we have to call .trigger('change') so the select element tells any listening javascript (ie the select2 plugin) that it's internal value has changed and the plugin should now update its display to match. ie, run this:
$('#'+fieldname).val(data.msg).trigger('change')
See more detailed documentation here

Related

Unable to see results with AsyncTypeahead with multiple option and renderInput

I'm trying to use a custom Input component on a Typeahead with the multiple option set. I see in the docs it says to "handle the refs" correctly, but I see no examples of how this is done. I'm not sure what to pass into referenceElementRef. Everything I've tried so far just doesn't render the options as I type. I see them in the DOM, but the opacity of the .rbt-menu is set to 0, so they're basically hidden.
Here's my code so far:
const divRef = React.useRef(null);
return (
<Col>
<div ref={divRef}>
<span className="uppercase">
<FormattedMessage id="d.customer" defaultMessage="Customer" tagName="h4" />
</span>
<AsyncTypeahead
multiple
id="customer-filter-input"
inputProps={{
'aria-label': 'Customer search',
style: { fontSize: '14px' },
}}
key={'customer-input'}
minLength={4}
isLoading={props.isLoadingcustomersSuggestions}
delay={300}
onSearch={(term: string) => handleFilterInputs(term, 'customers')}
size={'lg'}
options={dataSource}
labelKey={'defaultMessage'}
placeholder={intl.formatMessage({
id: 'companyName',
defaultMessage: 'Company name',
})}
onChange={(filterItem: any) => handleAutocompleteUpdate(filterItem, 'customer')}
renderInput={({ inputRef, referenceElementRef, ...inputProps }: any) => (
<Input
{...inputProps}
style={{ position: 'relative' }}
ref={(input: any) => {
inputRef(input);
referenceElementRef(divRef); // What do I put here?
}}
/>
)}
/>
</div>
</Col>
);
And this is what renders in the DOM after I type in the Typeahead and get results:
Any ideas or working examples of Typeahead using multiple and renderInput together?
EDIT:
Here's a codesandbox of what I'm seeing. I also see that the problem is also happening when multiple is NOT set. It seems to be an issue with using renderInput. Is it required that I also use renderMenu?
https://codesandbox.io/s/react-bootstrap-typeahead-async-pagination-example-forked-3kz3z
If you upgrade the typeahead version in your sandbox to the latest version (v5.1.1) and pass the input element to referenceElementRef, it works (note that you need to type some characters into the input for the menu to appear):
// v5.0 or later
renderInput={({ inputRef, referenceElementRef, ...inputProps }) => (
<Input
{...inputProps}
ref={(input) => {
inputRef(input);
referenceElementRef(input);
}}
/>
)}
The menu is rendered in relation to the referenceElementRef node by react-popper. In most common cases, the reference node will be the input itself. The reason there's both an inputRef and a referenceElementRef is for more complex cases (like multi-selection) where the menu needs to be rendered in relation to a container element around the input.
If using v4 of the component, the approach is similar, but the ref to use is simply called ref:
// v4
renderInput={({ inputRef, ref, ...inputProps }) => (
<Input
{...inputProps}
ref={(input) => {
inputRef(input);
ref(input);
}}
/>
)}

AngularJS ngModel directive in select

I am working on an angularjs project and i have a problem with the ngModel not binding within the select.But the same concept is working in another select tag and in the same html page.
Below is the code.
<select ng-model="selectedFont"
ng-options="font.title for font in fonts"
ng-change="onFontChange()">
</select>
onFontChange() function is placed in the controller.
Anyone help is highly appreciable...Thanks in advance.
Based on Tony the Pony's fiddle :
<div ng-app ng-controller="MyCtrl">
<select ng-model="opt"
ng-options="font.title for font in fonts"
ng-change="change(opt)">
</select>
<p>{{opt}}</p>
</div>
With a controller:
function MyCtrl($scope) {
$scope.fonts = [
{title: "Arial" , text: 'Url for Arial' },
{title: "Helvetica" , text: 'Url for Helvetica' }
];
$scope.change= function(option){
alert(option.title);
}
}
http://jsfiddle.net/basarat/3y5Pw/43/
First create data (can be local or from server) in Controller. And initialize the default value, which force the default item selected in HTML form.
// supported languages
$scope.languages = ['ENGLISH', 'SPANISH', 'RUSSIAN', 'HINDI', 'NEPALI'];
// init default language
$scope.language = 'ENGLISH';
Now in your HTML form
<select class="form-control" ng-model="language">
<option ng-repeat="language in languages">{{language}}</option>
</select>
The screenshot is here (note bootstrap CSS is used and not included here).
You can do a test in controller, whether the change is working
$scope.$watch('language', function (newVal, oldVal) {
console.log(oldVal + " -> " + newVal);
});
ENGLISH -> RUSSIAN
RUSSIAN -> SPANISH
SPANISH -> RUSSIAN
Hope this is helpful. Thanks!

Jquery tokeninput and unobtrusive validation in a MVC 4 application

I am stuck here and would very much appreciate help. I have a form in a razor view with a input field for current city which looks like this:
#Html.LabelFor(x => x.UserModel.CurrentCity)
#Html.TextBoxFor(x => x.UserModel.CurrentCity, new { #data_bind = "value: UserModel.CurrentCity ", #class = "city", #data_val = "true", #data_val_required="City is required" })
#Html.ValidationMessageFor(x => x.UserModel.CurrentCity)
I want autocomplete for this field and am using jquery token input plugin for this like:
$(".city").tokenInput('#Url.Action("AutocompleteCity", "Settings")',{ minChars: 2, tokenLimit: 1, hintText: "Type in a city" });
$(".city").tokenInput("add", {name: viewModel.UserModel.CurrentCity()});
Everything works fine except the clientside unobtrusive validation. The form gets posted even if CurrentCity is empty.
I also tried to change the MVC helpers to plain html:
<input data-val="true" data-val-required="City is required" type="text" class="city" data-bind = "value: UserModel.CurrentCity, attr: { name: 'UserModel.CurrentCity', id: 'UserModel.CurrentCity'}" />
<span class="field-validation-valid" data-valmsg-for="UserModel.CurrentCity" data-valmsg-replace="true"></span>
This approach prevents the form from being submitted but the validation-error class is not injected into the span and the error message does not show up.
Any suggestions?
The original input element you created is hidden. You will likely need to enable validation of hidden elements: jquery.validate v. 1.9 ignores some hidden inputs or https://stackoverflow.com/a/13295938/173225.

Symfony2 Forms: is it possible to bind a form in an "unconventional way"?

Imagine this scenario: in our company there is an employee that "play" around graphic,css,html and so on.
Our new project will born under symfony2 so we're trying some silly - but "real" - stuff (like authentication from db, submit data from a form and persist it to db and so on..)
The problem
As far i know, learnt from symfony2 "book" that i found on the site (you can find it here), there is an "automated" way for creating and rendering forms:
1) Build the form up into a controller in this way
$form = $this->createFormBuilder($task)
->add('task','text'),
->add('dueDate','date'),
->getForm();
return $this->render('pathToBundle:Controller:templateTwig',
array('form'=>$form->createview());
2) Into templateTwig render the template
{{ form_widget(form) }} // or single rows method
3) Into a controller (the same that have a route where you can submit data), take back submitted information
if($rquest->getMethod()=='POST'){
$form->bindRequest($request);
/* and so on */
}
Return to scenario
Our graphic employee don't want to access controllers, write php and other stuff like those. So he'll write a twig template with a "unconventional" (from symfony2 point of view, but conventional from HTML point of view) method:
/* into twig template */
<form action="{{ path('SestanteUserBundle_homepage') }}" method="post" name="userForm">
<div>
USERNAME: <input type="text" name="user_name" value="{{ user.username}}"/>
</div>
<div>
EMAIL: <input type="text" name="user_mail" value="{{ user.email }}"/>
</div>
<input type="hidden" name="user_id" value="{{ id }}" />
<input type="submit" value="modifica i dati">
</form>
Now, if into the controller that handle the submission of data we do something like that
public function indexAction(Request $request)
{
if($request->getMethod() == 'POST'){ // sono arrivato per via di un submit, quindi devo modificare i dati prima di farli vedere a video
$defaultData = array('message'=>'ho visto questa cosa in esempio, ma non capisco se posso farne a meno');
$form = $this->createFormBuilder($defaultData)
->add('user_name','text')
->add('user_mail','email')
->add('user_id','integer')
->getForm();
$form->bindRequest($request); //bindo la form ad una request
$data = $form->getData(); //mi aspetto un'array chiave=>valore
/* .... */
We expected that $data will contain an array with key,value from the submitted form.
We found that it isn't true. After googling for a while and try with other "bad" ideas, we're frozen into that.
So, if you have a "graphic office" that can't handle directly php code, how can we interface from form(s) to controller(s) ?
UPDATE
It seems that Symfony2 use a different convention for form's field name and lookup once you've submitted that.
In particular, if my form's name is addUser and a field is named userName, the field's name will be AddUser[username] so maybe it have a "dynamic" lookup method that will extract form's name, field's name, concat them and lookup for values.
Is it possible?
You can force Symfony2 to set the name of a form field, though I don't suggest it: $formBuilder->add('dummyfield', 'text', array( 'attr' => array('name' => 'yournamehere') ) );
Alternatively (also a bad idea), you can do this, which won't even let you use the form API: $this->getRequest()->get('whatever_the_field_name_is');
OR you can hackily add elements to the request based on the Sf2 generated names before binding it (copying the values that exist).
OR you can make use of the bind method of the form component (instead of bindRequest) as documented here.
But seriously...just use the formbuilder api. Your life will be easier, and isn't that what a framework is for? :)
Symfony 2 is based on twig as templating language. Let him use it :
{{ form_label(form.field) }}
will generate something like this :
<label for="field">field</label>
You can use all the available functions in order to render the form :
{{ form_label() }}
{{ form_widget() }}
{{ form_errors() }}
If you want to customize what is rendered by those functions, you can override twig templates as defined in the Symfony2 documentation.
Otherwise if you really want to something ugly, you can go for this kind of syntax :
{{ myform.vars.value.myField }}

Symfony2 TinymceBundle

I created an ArticleController to render a form with fields: title (text) and content (textarea), and everything works well until I add class="tinymce" to the textarea field in the template. then I get this error:
'An invalid form control with name='form[content]' is not focusable.'
I followed the documentation to add the 'class' attribute and the editor renders fine in the browser, its just when I submit the form I get the error.
Any ideas what could be causing this?
{{ form_errors(form) }}
{{ form_widget(form.title) }}
{{ form_widget(form.content, { 'attr': {'class': 'tinymce' }} ) }}
{{ form_rest(form) }}
<input type="submit" />
Apparently there is an issue with chrome regarding the attribute 'required = "true"'.
http://code.google.com/p/chromium/issues/detail?id=45640
I added 'formnovalidate = "true"' attribute to the submit button input field and it works fine
tinyMCE.init({
mode : "specific_textareas",
editor_selector : "mceEditor",
setup : function(ed) {
ed.onChange.add(function(ed, l) {
tinyMCE.activeEditor.getElement().value = tinyMCE.activeEditor.getContent();
});
}
});
I tried the suggestion from Musefan, and it only partly worked, but it got me experimenting.
Here's something that works for me. Tested on Firefox 10.0.1, IE9, and Chrome 17.
Where I'm setting tinyMCE.activeEditor.getElement().value = 'test' it can be any value other than ''. Not sure why that's true.
tinyMCE.init({
mode : "specific_textareas",
editor_selector : "tinymce",
setup : function(ed)
{
// This is needed when the textarea is required for html5
ed.onInit.add(function(ed)
{
tinyMCE.activeEditor.getElement().value = 'test'
});
},
});
The error happens when the WYSIWYG hides your textarea but the textarea is set to required field. You can set 'required' => false on your content textarea control when you build the form in order to disable browser's required check.
$builder->add("content", "textarea", array('required' => false));
tinyMCE will normally update the contents of the hidden textarea during the onsubmit-Event.
This event, however, is not fired when html5-validation is used and any input is invalid.
Therefore you will never get an empty and required textarea with tinyMCE on top to validate correctly unless you enforce the textarea to be updated before html5-validation starts.
I built a workaround for this bug which hopefully will be merged into the original repo anytime soon: https://github.com/stfalcon/TinymceBundle/pull/19
Building on musefans's response above.
I came here because I'm using Simple Form, Twitter Bootstrap, and tinymce-rails. If you're using tinymce-rails this setup you need to edit the line noted in is answer to your tinymce.yml file. Your final file should look similar to this.
theme_advanced_toolbar_location: top
theme_advanced_toolbar_align: left
theme_advanced_statusbar_location: bottom
theme_advanced_buttons3_add:
- tablecontrols
- fullscreen
plugins:
- table
- fullscreen
mode:
- specific_textareas