I have a multiple select2 Select field.
What I want is to add a new value to my select field. (after adding an entry to the database and bind this entry to the select field)
This is my code so far:
Blade template:
<div class="form-group {{ ($errors->first('projectTypes')) ? 'has-error' : '' }}">
<label for="projectTypes" class="col-md-2 control-label">{{ trans('project/project.fields.projectTypes') }}</label>
<div class="col-md-9">
{!! Form::select('projectTypes[]',
$projectTypes,
($project->projectTypes()->count() > 0) ? $project->projectTypes->lists('id')->toArray() : (isset($projectType)) ? $projectType->id : '',
['id' => 'projectTypes', 'class' => 'form-control', 'ng-model' => 'projectTypes', 'multiple' => 'multiple'])
!!}
<span id="helpBlock" class="help-block">{{ $errors->first('projectTypes') }}</span>
</div>
<div class="col-md-1">
<i class="fa fa-plus-square-o fa-2" data-toggle="modal" data-target="#addProjectType"></i>
</div>
The <i> tag toggles the modal. In the modal window I have an input field and a button (it works!):
<input ng-model="name" id="addProjectType" class="form-control" type="text" name="name" placeholder="Projekttyp">
<button type="button" class="btn btn-primary btn-embossed" ng-click="addProjectType(name)" data-dismiss="modal">Save changes</button>
So if I click on the button this will trigger a function in my angularJS code (this works!).
This is my angularJS Code:
$scope.projectTypes = [];
$scope.addProjectType = function(name) {
$http.post('/ajax/projecttype/addprojecttype', {
name: name
}).success(function(data, status, headers, config) {
$scope.projectTypes.push(data);
});
}
This do an ajax call to my laravel php function (this works!):
public function addProjectType(Request $request, Sentinel $sentinel) {
$name = $request->get('name');
$projectType = new ProjectType;
$projectType->name = $name;
$projectType->slug = $projectType->strSlug($name);
$this->created_by = $sentinel::getUser()->id;
$this->updated_by = $sentinel::getUser()->id;
$projectType->saveModel($request);
return Response::json($projectType, self::$OK);
}
But although I have declared my select field (ng-model="projectTypes")
and I declared the $scope.projectTypes and push the new Object to the $scope.projectTypes after the ajax call the select field won't update.
What am I doing wrong here?
Related
I am trying not to use formset in my form. Instead of that, I'm trying to create the form dynamically and save all forms data in the DB.
I can create a dynamic form, but whenever I create multiple forms in "create order", it always saves the last forms data. For example, once I create 3 forms, and after saving the form, the table shows me only 3rd form data, which means it does not save all data together.
views.py
def create_order(request):
from django import forms
form = OrderForm()
if request.method == 'POST':
forms = OrderForm(request.POST)
if forms.is_valid():
po_id = forms.cleaned_data['po_id']
supplier = forms.cleaned_data['supplier']
product = forms.cleaned_data['product']
part = forms.cleaned_data['part']
order = Order.objects.create(
po_id=po_id,
supplier=supplier,
product=product,
part=part,
)
forms.save()
return redirect('order-list')
context = {
'form': form
}
return render(request, 'store/addOrder.html', context)
forms.py
class OrderForm(forms.ModelForm):
class Meta:
model = Order
fields = ['supplier', 'product', 'part','po_id']
widgets = {
'supplier': forms.Select(attrs={'class': 'form-control', 'id': 'supplier'}),
'product': forms.Select(attrs={'class': 'form-control', 'id': 'product'}),
'part': forms.Select(attrs={'class': 'form-control', 'id': 'part'}),
}
HTML
<form action="#" method="post" id="form-container" novalidate="novalidate">
{% csrf_token %}
<div class="form">
<div class="form-group">
<label for="po_id" class="control-label mb-1">ID</label>
{{ form.po_id }}
</div>
<div class="form-group">
<label for="supplier" class="control-label mb-1">Supplier</label>
{{ form.supplier }}
</div>
<div class="form-group">
<label for="product" class="control-label mb-1">Product</label>
{{ form.product }}
</div>
<div class="form-group">
<label for="part" class="control-label mb-1">Part Name</label>
{{ form.part }}
</div>
</div>
<button id="add-form" type="button">Add Another Order</button>
<div>
<button id="payment-button" type="submit" class="btn btn-lg btn-success btn-block">
<span id="payment-button-amount">Save</span>
</button>
</div>
</form>
<script>
let poForm = document.querySelectorAll(".form")
let container = document.querySelector("#form-container")
let addButton = document.querySelector("#add-form")
let totalForms = document.querySelector("#id_form-TOTAL_FORMS")
let formNum = poForm.length-1
addButton.addEventListener('click', addForm)
function addForm(e){
e.preventDefault()
let newForm = poForm[0].cloneNode(true)
let formRegex = RegExp(`form-(\\d){1}-`,'g')
formNum++
newForm.innerHTML = newForm.innerHTML.replace(formRegex, `form-${formNum}-`)
container.insertBefore(newForm, addButton)
totalForms.setAttribute('value', `${formNum+1}`)
}
</script>
What causes this problem? How can I fix it?
I have created two text boxes and wrote the JSfunction to give alert msg that both the boxes together should be of 50 characters. Function called in onclick() event in Submit button. Also in controller Store() function, save the content of these two text boxes and validated with "required", then redirected to another page.
Problem is, if I give less than 50 characters it shows alert msg, but store the data even less than 50 characters given and redirected to specified page. If i give less than 50 characters, after showing the alert msg, it has to be in the same page until i give together 50 characters. It should ave the textboxes content only if more than 50 characters. Can anyone help me?
In create.blade.php
<form method="post" action="{{route('training.applicants.aim.create.process', $request->training_request_id)}}">
<div class="form-group" id="goal_group" >
<label class="col-form-label font-weight-bold" for="ziele[1]">Ziele 1</label>
<input type="text" name="ziele[1]" class="form-control form-control-sm #error('ziele.1') is-invalid #enderror" id="ziele.1" >
#error('ziele.1') <div class="invalid-feedback">{{ $errors->get('ziele.1')[0] }}</div> #enderror
</div>
<div class="form-group">
<label class="col-form-label font-weight-bold" for="ziele[2]">Ziele 2</label>
<input type="text" name="ziele[2]" class="form-control form-control-sm #error('ziele.2') is-invalid #enderror" id="ziele.2" >
#error('ziele.2') <div class="invalid-feedback">{{ $errors->get('ziele.2')[0] }}</div> #enderror
</div>
<div id="additional_goals"></div>
<hr/>
<div class="form-group row container-fluid" >
<div class="col">
<div class="col-2 float-right">
<br>
<button type="submit" style="position: absolute; right:0" class="btn btn-sm btn-primary" id="submit_btn" onclick="goal_validation()"> Submit </button>
</div>
</div>
</form>
Js function:
function goal_validation()
{
var l1=document.getElementById('ziele.1').value;
var l2=document.getElementById('ziele.2').value;
var Total=50-(l1.length +l2.length);
if(Total<50 && Total>0)
{
alert("U have to give minimum "+Total+" characters");
}
}
In controller store function:
public function storeGoals(TrainingRequest $antrag, Request $request)
{
$request->validate([
//'ziele.*' => 'required|string',
'ziele.1' => 'required|string',
'ziele.2' => 'required|string',
]);
$antrag->goals = isset($request->ziele) ? $request->ziele : NULL;
$antrag->save();
return redirect()
->route('Training.participation.mein', $request)
->with('Message', $Message);
}
You can try use strlen() function to find character length.
$request->validate([
//'ziele.*' => 'required|string',
'ziele.1' => 'required|string',
'ziele.2' => 'required|string',
]);
length1= strlen($request->ziele.1);
length2= strlen($request->ziele.2);
if((length1+length2) >= 50){
$antrag->goals = isset($request->ziele) ? $request->ziele : NULL;
$antrag->save();
return redirect()
->route('Training.participation.mein', $request)
->with('Message', $Message);
}
else{
return redirect()->back();
}
In the case of having many products, and user can dynamically adding new dropdown box. When I click submit, I want to get the value of "category[]" within the form only.
and this is the code:
<form name="store_category" method="post" enctype="multipart/form-data" action="{{ route('admin.product.category.store') }}">
{!!csrf_field()!!}
{!!""; $lang = session('locale') == "" ? "zh" : session('locale'); !!}
<div class="form-group category-select-container">
{!! Form::select("categories_$project->id[]", ${"categories_" . $lang}, null, ["class" => "input-sm"]) !!}
{{trans('string.Remove')}}
</div>
<div class="form-group">
<button type="button" class="btn btn-dark btn-add-more-category">{{trans('string.Add More')}}</button>
<button type="submit" class="btn blue btn-theme-colored">{{trans('string.submit')}}</button>
</div>
</form>
I've tried to rename the array name to something else, but when the user dynamically adding new dropdown box, it couldn't follow the number of the project for the row.
var template = '<div class="form-group category-select-container">'+
'{!! Form::select("categories_$project->id[]", ${"categories_" . $lang}, null, ["class" => "input-sm"]) !!}'+
'{{trans("string.Remove")}}'+
'</div>';
$('.btn-add-more-category').on('click', function(e){
e.preventDefault();
$(this).before(template);
})
I really would like to know what could be the output of this line in your Form::select()s
categories_$project->id[]
So anyway, if you would like to group your select tags you have to assign each of them with the same name. Suppose you are looping in an array of $projects. Each row would have
<form name="store_category" method="post" enctype="multipart/form-data" action="{{ route('admin.product.category.store') }}">
{!!csrf_field()!!}
#php $lang = session('locale') == "" ? "zh" : session('locale'); #endphp
<div class="form-group category-select-container">
{!! Form::select("category[]", ${"categories_" . $lang}, null, ["class" => "input-sm"]) !!}
{{trans('string.Remove')}}
</div>
<div class="form-group">
<button type="button" class="btn btn-dark btn-add-more-category">{{trans('string.Add More')}}</button>
<button type="submit" class="btn blue btn-theme-colored">{{trans('string.submit')}}</button>
</div>
</form>
Then next, you have to bind a click event to all your .btn-add-more-category. Let's say your parent table has a class of .table
<script>
$(function () {
$(".table").on("click", ".btn-add-more-category", function(e) {
var template = '<div class="form-group category-select-container"> ' +
'{!! Form::select("category[]", ${"categories_" . $lang}, null, ["class" => "input-sm"]) !!} ' +
'{{trans('string.Remove')}}' +
'</div>';
var container = $(this).parent();
$(template).insertBefore(container);
});
});
</script>
Also, I suggest that you move this line to your controller
$lang = session('locale') == "" ? "zh" : session('locale');
I seem to be overlooking something simple here but it has me stumped.
Why does nothing happen when i hit the submit button?
<section ng-controller="SavingsController as savingsCTRL">
<form name="createSavingForm" class="form-horizontal" novalidate>
<fieldset>
<!-- Title Box Start-->
<div class="form-group new-deal-form" show-errors>
<label for="title">Title</label>
<input name="title" type="text" ng-model="savingsCTRL.title" id="title" class="form-control" placeholder="Title" required>
<div class="sub-label">Enter the Title of the Deal.</div>
<div ng-messages="savingForm.savingsCTRL.title.$error" role="alert">
<p class="help-block error-text" ng-message="required">Saving title is required.</p>
</div>
</div>
<!-- Title Box End-->
<!--Submit Button Start-->
<div class="form-group buttons-cancel-submit">
<button class="btn btn-default " ng-click="savingsCTRL.cancel()">Cancel</button>
<input type="submit" class="btn btn-success " ng-click="savingsCTRL.create(); submitForm(createSavingForm.$valid)" >
</div>
</fieldset>
</form>
</div>
</div>
</section>
for simplicity i took most of the forms out but what else is wrong?
Savings Controller Function
// Create new Saving
$scope.create = function () {
$scope.error = null;
alert("create");
// Create new Saving object
var saving = new Savings({
title: this.title,
details: this.details,
retailer: this.retailer,
price: this.price,
link: this.link,
image: $scope.user.imageURL,
urlimage: this.urlimage,
tags: this.tags
//startdate: this.startdate,
//enddate: this.enddate
});
// Redirect after save
saving.$save(function (response) {
$location.path('savings/' + response._id);
// Clear form fields
$scope.title = '';
$scope.details = '';
$scope.retailer = '';
$scope.price = '';
$scope.link = '';
$scope.image = '';
$scope.urlimage = '';
$scope.tags = '';
}, function (errorResponse) {
$scope.error = errorResponse.data.message;
});
};
Main issue is, you are mixing controller as syntax with $scope.
According to documentation, we should use this instead of $scope.
... binds methods and properties directly onto the controller using this: ng-controller = "SettingsController1 as settings"
Than, submitForm is not a predefined method, it should be defined in controller first
this.submitForm = function(isValid){
console.log('Submitting form: ' + isValid)
}
In addition to that, bind that to form with ng-submit= "savingsCTRL.submitForm(createSavingForm.$valid)"
See Plunker, with working code. (I took ng-click="savingsCTRL.create()", since we don't have all parts of your application)
Bind the form submit event to ng-submit.
Example: ng-submit="submitForm(createSavingForm.$valid)"
I'm having trouble in wanting to create multiples of the same html that I render in a certain class. For example, I have a div that might look like this
[Header goes here, is a input field] [Dropdown]
[TextArea]
[Submit]
[Add another field]
On add another field, I would like to clone this view and be able to add as many again.
Here's what I have so far:
var UpdateForm = React.createClass({
handleSubmit : function(e) {
e.preventDefault();
var title = React.findDOMNode(this.refs.title).value.trim();
var date = React.findDOMNode(this.refs.date).value.trim();
var body = React.findDOMNode(this.refs.body).value.trim();
if(!title||!date || !body ) {
return;
}
this.props.onSubmit({title:title, date : date, body : body});
React.findDOMNode(this.refs.title).value = '';
React.findDOMNode(this.refs.date).value = '';
React.findDOMNode(this.refs.body).value = '';
//React.findDOMNode(this.refs.sub).value = '';
},
render: function() {
return(
<div id = "This is what I want to duplicate on each button click">
<form className="form-horizontal" onSubmit={this.handleSubmit}>
<div class="form-control">
<label className="col-sm-0 control-label ">Title:</label>
<div class="col-sm-5">
<input className = "form-control" type = "text" placeholder="Title...." ref = "title"/>
</div>
</div>
<div class="form-control">
<label className="col-sm-0 control-label ">Date:</label>
<div class="col-sm-5">
<input className = "form-control" type = "text" placeholder="Date...." ref = "date"/>
</div>
</div>
<div className="form">
<label htmlFor="body" className="col-sm-0 control-label">Report Body:</label>
<div className="column">
<textarea className = "ckeditor" id = "ckedit" ref = "body"></textarea>
</div>
</div>
<div class="form-group">
<label className="col-sm-0 control-label"></label>
<div class="col-sm-5">
<input type = "submit" value="Save Changes" className = "btn btn-primary" />
</div>
</div>
</form>
<div className="btn-group">
<button type="button" className="btn btn-danger">Assign to</button>
<button type="button" className="btn btn-danger dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<span className="caret"></span>
<span className="sr-only">Toggle Dropdown</span>
</button>
<ul className="dropdown-menu">
{
this.props.forms.map(function(form){
return (
<li>{form}</li>
)})}
</ul>
<button className="btn btn-success btn-block" onClick={this.addInputField}>Add Subform</button>
</div>
</div>
);
}
});
What I think I need to add:
addDiv: function(e) {
e.preventDefault();
//have a array of divs?
//push a the same div into it?
//then set state of that array?
}
I know in jquery I could just write a function that appends this markup whenever I hit a button, but i don't know how to think about it here at all.
I think what you want is to have a button which add another header-date-body-Component to the form, which should then also be submitted, right?
If so then you need to think more in components. Have one Component which handles the form. Have one around that which handles adding other forms.
<ReportDialog>
<ReportForm>
<ReportForm>
<button onClick={this.addReport}>Add another</button>
</ReportDialog>
To accomplish the multiple ReportForms you need to think about the data in your component, which are reports (I assume). So you need a state in ReportDialog which keeps track of your reports. so at the start of the app you have one report:
getInitialState: function () {
return {
reports: [{ title: '', body: '', date: new Date() }]
};
}
So in addReport you then need to change the state and add another report. To have these reports rendered you already used map, but this time you need to loop over the reports in your component and return a ReportForm for each report.