What i know
In a modal creation object i know how add an attachment or image because all <input> are inside a form and when user click the submit button the form action trigger the controller that manage inputs data.
For Example:
<form id="formId" t-attf-action="/my/object/#{slug(object)}/create" method="post" enctype="multipart/form-data">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<input type="hidden" name="object" t-att-value="object"/>
<input type="text" name="text" class="o_website_form_input form-control"/>
<input type="file" name="image" class="o_website_form_input form-control" accept="image/*"/>
<input type="submit" class="btn btn-success" value="Create/"/>
</form>
Will trigger the following controller:
#route(['/my/object/<model("object.model"):object>/create'],
type='http', auth="user", methods=['POST'], website=True)
def object_create(self, object, **post):
if not object:
return request.render("website.404")
attachment = post.get('image')
text = post.get('text')
values = {
'text': text,
}
# If present get image data from input file
if attachment:
data_image = base64.b64encode(attachment.read())
values['image'] = data_image
request.env['object.model'].create(values)
# Redirect to the details page with new value
string_url = '/my/object/view/' + slug(object)
return werkzeug.utils.redirect(string_url)
So, now we have a sync POST that create object with text and image with a redirect to the create object.
Now, the question is:
How manage records with images or attachments update?
For simple record update i use this methods:
1) a modify button that show hidden <input> or <textarea> that will
take new values
2) an on.('change', '.class-to-monitorate') that populate an object like
point 3)
3) dataToSend = {}
It become something like:
dataToSend = {object_id: {values from input}} --> This is Good for write() inside controller
4)An ajax.jsonRpc("/my/path/for/update/value", "call", dataToSend)
The problem is that with controller type JSON and <input type="file"> i don't know how pass files.
It's possible to use a controller type="http" and send data like a <form>?
So i can receive all the changed <input type="file"/> and store them without refreshing the entire page every time.
EDIT
Here the JS that populate dataToSend object
// onChange bind that manage confirmity line values save
$(document).on("change", ".conformity-line-value", function () {
let value = $(this).val();
let name = $(this).attr('name');
let type = $(this).attr('type');
let non_conformity_line_id = Number($(this)
.closest('div.non-conformities-line')
.find("input[name='non_conformity_line_id']").val());
//If the dict for this line does not exist create it
if (!dataToSaveConformities[non_conformity_line_id]) {
dataToSaveConformities[non_conformity_line_id] = {}
}
//Add changed elements into dic to corresponding line
switch (name) {
case 'name':
dataToSaveConformities[non_conformity_line_id]['name'] = value;
if (value === '') {
$(this).addClass('error_input');
} else {
$(this).removeClass('error_input');
}
break;
case 'non_conformity_note':
dataToSaveConformities[non_conformity_line_id]['non_conformity_note'] = value;
break;
default:
break;
}
});
The class .conformity-line-value is set to all input,textarea,select,checkbox that i need to monitorate if the user change them.
Here the JS function that call controller that save data:
function save_changed_values() {
if (!isEmpty(dataToSaveConformities)) {
ajax.jsonRpc("/my/sale_worksheet_line/non_conformity/update/value", "call", dataToSaveConformities)
.then(function (data) {
//Clear data to send
for (var member in dataToSaveConformities) delete dataToSaveConformities[member];
if (data.error) {
//FIXME: check that case or manage it
$('.non-conformities-div').load(window.location + " .non-conformities-div>*", function () {
$('select.js-conformities-read-multiple').select2();
});
} else {
$('.non-conformities-div').load(window.location + " .non-conformities-div>*", function () {
$('select.js-conformities-read-multiple').select2();
});
}
});
}
}
I try to take the base64 of image from <input type="file"> and put it inside sended object (parsed as JSON)
But in the controller i receive an empty value inside **post
Related
Good evening all!
I am currently working with google maps api.
The google maps asks for a json format to set directions.
Everything works fine if i make my own json object, but i would like to retrieve data from input fields and store it in the json object.
Right now i can retrieve 1 value from the input field and store it. But i woud like to retrieve multiple values. This is needed to set an direction on the maps. I need to find a way to store the multiple values in an json object as array. Correct my if i wrote some things wrong, i am not a expert :)
"key" : "Array"
See below for the example + Code
This is what i need to try to get:
A user comes to the page and sees 2 input fields, he fills in Amsterdam and Rome but he always needs Paris. So the user press the + icon. Another input field appears and he fills in Paris. when the user submits this below must be the json result from the input fields
"locatie" : ["Berlin", "Amsterdam", "Paris", "Rome"]
This is is my form:
<form onsubmit="return make_json(this);">
Locatie: <input type="text" name="locatie">
<input type="submit" name="" value="Make Trip">
</form>
My js function:
function make_json(form) {
var json = {
"locatie" : form.locatie.value
// this is what works and what i would like to retrieve from multiple input fields
//"locatie" : ["Paris", "Amsterdam"]
};
return json;
}
In the google maps api i call the function and use the json:
var jsonArray = make_json();
You can declare an array and push the values to it when the button is clicked.
// Declare location array
var locations = [];
// Button bindings
var locationButton = document.getElementById("addNewLocation");
locationButton.onclick = addNewLocation;
var displayJsonButton = document.getElementById("displayJsonObject");
displayJsonButton.onclick = displayJsonObject;
// Button functions
function addNewLocation() {
var location = document.getElementById("locationText").value;
locations.push(location);
document.getElementById("locationText").value = "";
}
function makeJsonObject() {
var json = {
location : locations
}
return json;
}
function displayJsonObject() {
var obj = makeJsonObject();
console.log(obj.location);
}
<input id="locationText" type="text" />
<button id="addNewLocation">Add</button>
<button id="displayJsonObject">Display JSON</button>
The results will be populated in the console. I have also returned the JSON object for you in the displayJsonObject() function, which you could use to pass to the API.
You can also try this, if you want to keep showing the locations entered before adding new location.
function addInput() {
var input = document.createElement('input');
input.setAttribute("type", "text");
input.setAttribute("name", "locatie[]");
inputs.appendChild(input);
}
function make_json() {
var form = document.querySelector("form");
var values = [];
var locations = form['locatie[]'];
if (locations.length) {
locations.forEach(function(input) {
values.push(input.value);
});
} else {
values.push(locations.value);
}
var json = {
"locatie": values
};
console.log(json);
return json;
}
<form>
Locatie:
<div id="inputs">
<input type="text" name="locatie[]">
</div>
<button onClick="addInput()">+</button>
<input type="submit" value="Make Trip" onClick="make_json(this)">
</form>
Note: Take care of UI. If user enters more number of inputs, UI may deform.
I have a dropdownlist in my View. I need to enable the user to select a value from the dropdownlist and click a button/ActionLink to call another action method in the same controller. The values that needs to be passed to the new ActionMethod are the ID of the selected Value from the dropdownlist and also the ID of the model which is being passed into the View. The model and the Dropdownlist are not linked together by any means.
I have tried onchnage = document.location.href to set the path of the action method and pass a single value to the action method. But the issue with document.location.href is that it appends the url to the existing url which is not appreciated; i.e, the final url turns out be localhost:port/controller1/action1/controller1/action2 which should have been simply localhost:port/controller1/action2
I am looking for a way where it could be done without using javascript as I have already tried it.
Code in the View
#using (Html.BeginForm("Copy","SetValues",FormMethod.Post))
{
<p>
#Html.DropDownList("OptionValueID", null, "Select")
<input type="submit" value="Copy" />
//This is the preferable method though
#*#Html.ActionLink("Copy", "Copy", "SetValues", new { #OptionValueID = #ViewBag.id,#CopyID = CopyDDL.SelectedValue},null)*#
</p>
}
The copy function is going to take two arguments: Id of the selected item and ID that is being passed through ViewBag.id
The View that is being returned by View would a different View
JavaScript that I have tried
<script language="javascript" type="text/javascript">
function copy(_OptionValueID)
{
var url = "/SetValues/Copy";
$.ajax({
url: url,
data: { copyid: _OptionValueID},
type: "POST",
success: function (data) { }
});
response();
}
</script>
It doesn't evaluate at all.
Action Method that calls this View
public ActionResult Index(int id)
{
var ov = db.OptionValue.Include(x => x.Option).FirstOrDefault(x => x.OptionValueID == id);
var opid = ov.OptionID;
var op = db.Option.Include(x => x.TechnicalCharacteristic).FirstOrDefault(x => x.OptionID == opid);
var tcid = op.TechnicalCharacteristicID;
var tc = db.TechnicalCharacteristic.Include(x => x.TcSets).FirstOrDefault(x => x.TechnicalCharacteristicID == tcid);
var tcset = tc.TcSets;
var opv = db.OptionValue.FirstOrDefault(x => x.OptionValueID == id);
ViewBag.OptionValue = opv.OptionVal;
ViewBag.Option = opv.Option.OptionName;
ViewBag.Lsystem = opv.Option.Lsystem.LsystemName;
ViewBag.FamilyName = opv.Option.Lsystem.LsystemFamily.FamilyName;
ViewBag.OptionValID = id;
ViewBag.OptionID = opv.OptionID;
var setValue = db.SetValue.Where(x=>x.OptionValueID==id).OrderBy(x=>x.TcSet.SetName);
ViewBag.OptionValueID = new SelectList(db.OptionValue.Where(x=>x.OptionID==opid), "OptionValueID", "OptionVal");
return View(setValue.ToList());
}
I ahve checked most question relating to this, but none had the overhead of passing two parameters without using a model.
UPDATE: making it more clear
public ActionResult copy(int OptionValueID,int CopyID)
{
//do Something
return View("Error");
}
Above is the Copy Method
OptionValueID = ViewBag.OptionValID //Got from the Action Method Index of SetValues
CopyID = Value from the DropDownlist
Edit Based on Answer
#using (Html.BeginForm("Copy","SetValues",FormMethod.Post))
{
<p>
#Html.DropDownList("CopyID", null, "Select")
<button type="submit" id="Copy" data-id="#ViewBag.OptionValID"> Copy </button>
</p>
}
now the page is being redirected but the no parameters are being passed. Should I be adding routevalues?
You cannot do it without javascript. Your ActionLink() method is parsed on the server before its sent to the client, so any route values are the initial values in the controller, not any edited values the user makes in the view. In order to respond to client side events you need javascript.
You can use ajax to post the values to the server method.
Include a button and handle its click event
<button type="button" id="Copy" data-id="#ViewBag.id">Copy</button>
Script
var url = '#Url.Action("Copy", "SetValues")';
$('#Copy").click(function() {
var optionID = $(this).data('id');
var copyID = $('#OptionValueID').val();
$.get(url, { OptionValueID: optionID, copyID : CopyID }, function(response) {
// do something with the response
});
});
or alternatively if you wanting to redirect, then replace the $.get() with
location.href = url + '?OptionValueID=' + optionID + '&CopyID=' + copyID;
Edit
Based on revised question and comments, if you wanting to post and redirect, there is no need for any javascript or the link. The dropdownlist needs to be #Html.DropDownList("CopyID", null, "Select") so that its selected value is bound to method parameter int CopyID and since the OptionValueID is not edited, then either add its value as a route parameter in the form
#using (Html.BeginForm("Copy", "SetValues", new { OptionValueID = ViewBag.OptionID }, FormMethod.Post))
or add a hidden input for the value
<input type="hidden" name="OptionValueID" value="#ViewBag.OptionID" />
I am trying to update an json object value from a textbox using angular and I'm not sure what the best way to go about it is.
This is the json object...
$scope.productAttributes = {
"CostRequirements":[
{
"OriginPostcode": 'NW1BT',
"BearerSize":100
}
]
}
And when a use types in a text field and clicks a button, I would like to grab that textfield value and pass it into the json object to replace the postcose value (OriginPostcode) I tried to pass in a scope variable but that didnt work.
<input type="text" placeholder="Please enter postcode" class="form-control" ng-model="sitePostcode"/>
And this is the fucntion that is fired when the user clicks a button to submit the json
var loadPrices = function () {
productsServices.getPrices1($scope.productAttributes)
.then(function (res) {
$scope.selectedProductPrices = res.data.Products;
// $scope.selectedProductAddOns = res.data.product_addons;
})
.finally(function () {
$scope.loadingPrices = false;
$scope.loadedPrices = true;
});
};
Could anyone tell me what I need to do to put the user input in the textbox into the json object?
Many thanks
What we don't see is the function that runs the update with the button. It should look something like this
// your HTML button
<button ng-click='updateThingy()'>Update</button>
// your HTML input
<input type="text" ng-model="myObject.sitePostcode"/>
// your controller
$scope.myObject = { // ties to the ng-model, you want to tie to a property of an object rather than just a scope property
sitePostcode : $scope.productAttributes.CostRequirements[0].OriginPostcode // load in post code from productAttributes
};
$scope.updateThingy = function(){
$scope.productAttributes.CostRequirements[0].OriginPostcode = $scope.myObject.sitePostcode;
};
Here is a demo plunker for updating a value on button click, hope it helps out.
http://plnkr.co/edit/8PsVgWbr2hMvgx8xEMR1?p=preview
I guess loadPrices function is inside your controller. Well, then you should have sitePostCode variable available inside your controller and your function. So you just need to inject that value inside $scope.productAttributes.
$scope.productAttributes.sitePostCode = $scope.sitePostCode;
This you need to put it before you make the productsServices.getPrices1 call.
var loadPrices = function() {
$scope.productAttributes.sitePostCode = $scope.sitePostCode;
productsServices.getPrices1($scope.productAttributes)
.then(function(res) {
$scope.selectedProductPrices = res.data.Products;
// $scope.selectedProductAddOns = res.data.product_addons;
})
.finally(function() {
$scope.loadingPrices = false;
$scope.loadedPrices = true;
});
};
Let me know if it worked.
I'm new to Javascript and Jquery so please excuse my ignorance. I'm trying to get my form fields to auto populate city and state based on zip code using JSON data I am pulling from an online .asp database. I am getting a successful JSON response with data that I can view in my dev tools window, but cannot get it to populate the fields on my form.
My Code is:
$(function() {
var cache = {};
var container = $("#validate");
var errorDiv = container.find("div.text-error");
/** Handle successful response */
function handleResp(data)
{
// Check for error
if (data.error_msg)
errorDiv.text(data.error_msg);
else if ("City" in data)
{
// Set city and state
container.find("input[name='City']").val(data.City);
container.find("input[name='State']").val(data.State);
}
}
// Set up event handlers
container.find("input[name='zipcode']").on("keyup change", function() {
// Get zip code
var zipcode = $(this).val().substring(0, 5);
if (zipcode.length == 5 && /^[0-9]+$/.test(zipcode))
{
// Clear error
errorDiv.empty();
// Check cache
if (zipcode in cache)
{
handleResp(cache[zipcode]);
}
else
{
// Build url
var url = "http://dev.xxx.com/ASPFetchers/GetSPROCAsXML.asp?SPROC=EG_GetZipCodeInfo%20/"+(zipcode)+"/&F=JSON";
// Make AJAX request
$.ajax({
"url": url,
"dataType": "json"
}).done(function(data) {
handleResp(data);
// Store in cache
cache[zipcode] = data;
}).fail(function(data) {
if (data.responseText && (json = $.parseJSON(data.responseText)))
{
// Store in cache
cache[zipcode] = json;
// Check for error
if (json.error_msg)
errorDiv.text(json.error_msg);
}
else
errorDiv.text('Request failed.');
});
}
}
}).trigger("change");
});
My markup on my form is as follows:
<div id="validate">
<label>Zip Code</label>
<input type="text" name="zipcode" id="zipcode" size =" 5" maxlength = "5" />
<div class="text-error"></div>
<label>City</label>
<input type="text" name="City" id="City" />
<label>State</label>
<input type="text" name="State" id="State" />
<script type="text/javascript" src="../zip/includes/zip2.js"></script>
</div>
</div>
The JSON I can view in my dev tools is(based on zipcode 06702):
{"items":[{"City":"WATERBURY","County":"NEW%20HAVEN","State":"CT","StateName":"CONNECTICUT","Latitude":"0.7252836","Longitude":"-1.274794"},
Can anyone help me solve how to get the information from this string and have it populate the "City" and "State" field? Thank You for your time and knowledge.
If you look at the data you posted here, you will need to use the items array inside of your data.
container.find('input[name="City"]').val(data.items[0].City);
container.find('input[name="State"]').val(data.items[0].StateName);
The object that is returned looks is an array of objects.
So first get the items array and refer the 1st item inside it.
function handleResp(data) {
// Check for error
if (data.error_msg)
errorDiv.text(data.error_msg);
else if ("City" in data) {
var info = data.items[0];
// Set city and state
container.find("input[name='City']").val(info.City);
container.find("input[name='State']").val(info.State);
}
}
I have a form:
<form>
<input type="text" name="email" >
<input type="text" name="phone" >
<input type="button" value="ok" />
</form>
When clicking the button, I'd like to copy the form values to a corresponding model.
I've found Backbone.ModelBinder which will automatically copy values to model whenever the values are changed, but that's not what I want, I just want to copy the values when the button is clicked.
write a custom function into the view where the form is located and bind it to the ok click event:
events: {
...
'click input[name="ok"]': 'copyFormToModel'
...
},
...
copyFormToModel: function() {
var email = $('input[name="email"]').val();
var phone = $('input[name="phone"]').val();
// Perform some sort of validation
this.model.email = email;
this.model.phone = phone;
}
This isn't the prettiest answer, but if you have just one small form in your page, then using some library or plugin might be a bit overkill. If you want to use a plugin or library, then for your case I think backbone-forms could do the trick. It features updating the model bound to the form with a method call rather than every time fields are updated.
This code may be you need:
events: {
...
'click input[value="ok"]': 'collectData2Model'
...
},
...
//suppose employee is your model
collectData2Model: function(e) {
var employee = new Employee();
var attr = {};
$('input').each(function(){
var input = $(this);
attr[input.attr('name')] = input.val();
});
employee.bind('error',function(model,error){
alert(error);
});
// set method will automatically call the model's validate method
employee.set(attr);
}