w2ui is ignoring the value on the input tag.
How do I get it to use the value?
It reads the selects just fine.
jsfiddle.net
<div id="form" style="width: 750px;">
<div class="w2ui-page page-0">
<div class="w2ui-field">
<label>First Name:</label>
<div>
<input name="first_name" type="text" value="John" />
</div>
</div>
</div>
<div class="w2ui-buttons">
<button class="w2ui-btn" name="reset">Reset</button>
<button class="w2ui-btn" name="save">Save</button>
</div>
</div>
$(function() {
$('#form').w2form({
name: 'form',
url: 'server/post',
fields: [
{ field: 'first_name', type: 'text', required: true }
],
actions: {
reset: function() {
this.clear();
},
save: function() {
this.save();
}
}
});
});
If I have to write JavaScript. How would I access the fields?
You can access the value of the input with form.record.
In your case w2ui.form.record.first_name (where form is the name of your w2form).
In your save event you can access the record with this.record, e.g.:
save: function() {
console.log(this.record);
console.log(this.record.first_name);
this.save();
}
additionally, As documentation of w2ui , you can set the value of input field
w2ui.Your_Form_Name.record['You_InputField_Name'] = The_New_value;
and then call form refresh to update both html and object, but this has issue where it clear the previous drop list select , so do set the new value with code as the following to avoid use refresh and keep pre-select in drop list
$('#InputFiled_Name').val(The_New_Value);
w2ui.Your_Form_name.record['Your_InputField_Name'] = The_New_Value;
Related
I have a form which is showing multiple input based on database data and I need to get each input value when I submit my form.
Code
<form ref="form" :model="form">
<div class="row">
<div
class="col-md-6"
v-for="(field, index) in fields"
:key="index"
>
<input
class="form-control"
v-model="form.field"
:placeholder="field.title"
/>
</div>
</div>
<vs-button
class="mt-3"
#click="onSubmit"
native-type="submit"
gradient
>
Generate
</vs-button>
</form>
data() {
return {
fields: [],
form: {
field: [],
},
};
},
Issue
My issue is that currently when I fill 1 input others get the same value, I need to fill each input individually.
Screenshots
Any idea?
You're using your v-model pointing to form.field, try to use v-model="form.field[index]"
In my code I create a lot of elements dynamicly on serverside, store the html of these elements in a javascript object,remove them and dynamicly/conditionally add them to different parts of the page.
For one particular element I want a data binding, such that I can refer to that binding in a v-if directive. However, if I add the v-bind on the server side, it gets lost after I copy the html.
Since I do only add the elements in my javascript code, I can not register the v-bind in my template. Neither can I provide the content in a component, since it is not static but relys on the input from the server.
How do I register the binding?
Sample Code:
Dynamicly generated form elements (server side):
<div id="archive" style="display: none;">
<div><input type="text" name="purpose" v-bind:value="purpose" id="id_purpose"></div> <!-- v-bind has no effect -->
<div><input type="text" name="purpose__iexact" id="id_purpose__iexact"></div>
<div><input type="text" name="purpose__contains" id="id_purpose__contains"></div>
<div><input type="text" name="purpose__icontains" id="id_purpose__icontains"></div>
<div><input type="text" name="purpose__in" id="id_purpose__in"></div>
...
</div>
Code to copy the html:
var input = {};
var archive = document.getElementById('archive');
for(var i = 0; i < archive.children.length; i++) {
var div = archive.children[i];
input[div.firstChild.name] = div.innerHTML
}
archive.parentNode.removeChild(archive);
Template code to display a certain input field dynamicly (client side):
<div class="inline" v-html="input[SOME CONDITIONAL COMPUTATIONS]"></div>
the correct way to rendering vue scene is:
<template>
<div>
<input type="button" value="Add new item" #click="addItem">
<hr>
<div v-for="(item,index) in data" :key="index">
<span v-html="item.html"></span>
<h3>Model data {{item.model}}</h3>
<input type="text" v-model="item.model">
<input type="button" value="Click me" #click="item.action(index)">
<input v-if="item.show" type="button" value="Remove me" #click="removeItem(index)">
</br>
</div>
</div>
</template>
<script>
export default {
data() {
return {
item: {
model: "",
show:true,
html: "<b>mydata html</b>",
action: function(index) {
console.log(`Clicked ${index} element.`);
}
},
data: [
{
model: "",
show:false,
html: "<b>mydata html</b>",
action: function(index) {
alert(`Clicked ${index} element.`);
console.log(`Clicked ${index} element.`);
}
},
{
model: "",
show:true,
html: "<b>mydata html</b>",
action: function(index) {
alert(`Clicked ${index} element.`);
console.log(`Clicked ${index} element.`);
}
}
]
};
},
methods: {
addItem() {
let item = Object.assign({}, this.item); // other way dublicating Observer
this.data.push(item);
},
removeItem(index){
this.data.splice(index,1)
}
}
};
</script>
You can add a show boolean prop to item object and v-if="" atribut to div to hide it.
I hope this example will help you.
I want to render some forms and bind them to Vue.
forms are listed on json Like this.
formslist:[
"<input type='text' name='item1' v-model='item1'>",
"<input type='text' name='item2' v-model='item2'>",
]
I could render them but couldn't bind.
Template is this.
<div v-for="form in formslist">
<div v-html="form"></div>
</div>
Later, I understood that html added by "v-html" can't use data bindings.
But then I don't have no ideas how to do this.
Would anyone teach me good solution?
Sorry for lack of words.
I wrote code like this but "item1" and "item2" are not binded.
js:
new Vue({
el: '#app',
data() {
return {
formData: {},
formslist:
// this list is got by ajax as neccessary
{
"item1": "<input type='text' name='item1' v-model='formData.item1'>",
"item2": "<input type='text' name='item2' v-model='formData.item2'>",
}
};
},
methods: {
submit() {
alert('formdata: ' + JSON.stringify(this.formData));
// submit data to backend
// e.g. axios.post(...).then(...).catch(...);
}
}
})
html:
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div id="app">
<form name="myForm" #submit.prevent="submit">
<div class="form-group">
<label>Firstname</label>
<input class="form-control" v-model="formData.firstName" type="text">
</div>
<div class="form-group">
<label>Lastname</label>
<input class="form-control" v-model="formData.lastName" type="text">
</div>
<div class="form-group">
<label>Description</label>
<textarea class="form-control" v-model="formData.description"></textarea>
</div>
<div class="form-group" v-for="(form, name) in formslist">
<label>{{name}}</label>
<div v-html="form"></div>
</div>
<button type="submit">
Submit
</button>
</form>
</div>
Vue.js is model/data oriented - have a look at the docs to learn more about it.
So create a model where you're storing your form data and then use that model to submit the data or do anything you like with the data.
Please have a look at a basic example below or at this fiddle.
Update 01.07.2017
OK, now I understand what you're trying to do.
Please find my updated code below or at the fiddle (same link).
You could also use a form generator like vue-form-generator. It's doing the same as my demo - just fewer coding required.
How does it work?
The form will be rendered with a template that is getting the data from a model that you can get from the server.
The type of the input can't be bound with :type because that's not supported with v-model - there was an error message when I tried that. So it's a bit more to write but it should be clear how this works. Add similar template tags for other types.
To further improve the model, you could also store the top-level of your form, so you can customize that display class as well. e.g. something like:
{
formName: 'myForm',
className: 'form-horizontal',
items: [...] // same array as before
}
If you need to group some inputs or display them differently you can add more properties to the model and more logic to the template.
const formRenderModel = [{
type: 'text',
modelName: 'firstName',
className: 'form-control',
labelText: 'First name',
required: true
}, {
type: 'text',
modelName: 'lastName',
className: 'form-control',
labelText: 'Last name',
required: true
}, {
type: 'text',
modelName: 'description',
className: 'form-control',
labelText: 'Description',
required: true,
pattern: '.{10,}', // minimum 10 characters
validationMessage: 'Minimum 10 characters required'
}];
new Vue({
el: '#app',
data() {
return {
formData: {}
};
},
created() {
// later axios.get('/form-render).then(...).catch(...);
// now just a constant
this.formRenderModel = formRenderModel;
},
methods: {
submit() {
console.log('formdata', this.formData);
// submit data to backend
// e.g. axios.post(...).then(...).catch(...);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<div id="app">
<form name="myForm" #submit.prevent="submit">
<div v-for="inputModel in formRenderModel">
<label>{{inputModel.labelText}}</label>
<template v-if="inputModel.type == 'text'">
<input type="text" v-model="formData[inputModel.modelName]"
:class="inputModel.className"
:pattern="inputModel.pattern"
:title="inputModel.validationMessage"
:required="inputModel.required" />
</template>
<!-- add more templates for radios, checkboxes, .. -->
</div>
<button type="submit">
Submit
</button>
</form>
</div>
I want to grab data other than id or text when an element is selected. The data is retrieved from some source when user puts in some values. All the data fetching and populating works properly. Previously just to get it working, I have just concatenated the "custom" value with some delimiter into the id then later parsed it out, but for the specs of what I want to do, I can't do that anymore. This is basically the code I have so far:
JS:
function convertResult(result) {
return {
id: result.p0,
text: result.p1,
custom: result.p2
};
}
searchBox.select2({
width: '100%',
minimumInputLength: 3,
placeholder: 'Search',
ajax: {
url: {someUrl},
delay: 350,
dataType: 'json',
data: function data(params) {
return { q: params.term }
},
processResults: function processResults(data) {
return { results: $.map(data.results, convertResult); }
}
}
});
searchBox.on("change", function (e) {
var selVal = $(this).val(); //this gets me the id
var selText = $(this).text(); //this gets me the text
// grab the "custom" property from the selected element
}
(cs)HTML:
<div class="form-horizontal">
<div class="form-group">
<label class="col-sm-2 control-label> Dropdown </label>
<div class="col-sm-10">
<select data-url='#Url.Action("get")' class="form-control ">
<option value="" selected="selected"> </option>
</select>
</div>
<div class="form-group">
<label class="col-sm-2 control-label"> Readonly Textfield</label>
<div class="col-sm-10">
<input type="text" class="form-control custom" style="width: 100%;" readonly="readonly">
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<button type="submit" class="btn btn-primary">
Submit
</button>
</div>
</div>
</div>
So what I want to do is once an element is selected from the select2 dropdown, populate the readonly textfield with the value saved in custom. When I look at the developer window for my browser I can't seem to find the value on the page. But when debugging, I can see the Json Object with custom value. I have considered scanning through the JSON to find the information I need, but I want to avoid that if possible. How do I go about extracting this information otherwise?
I would like to be able to edit and display complex model in a <textarea> element. Here's the HTML piece for generating model's fields dynamically from JSON response:
<p>parent uuid*: </p>
<input ng-model="parentUuid" capitalize type="text" placeholder="String"
class="form-control" style="width:200px; display: inline-block;"/> <br/>
<p>resource*:</p>
<select ng-model="childResource" ng-change="loadResourceFields(childResource)"
class="form-control" style="width:300px; display: inline-block;">
<option ng-repeat="childResource in restResources">{{childResource}}</option>
</select>
<div ng-repeat="field in childFields">
<div ng-show={{!field.isEnum}}>
<p ng-show={{field.isRequired}}>{{field.name}}*: </p>
<p ng-show={{!field.isRequired}}>{{field.name}}: </p>
<input type="text" ng-model="createChildResource[field.name]"
class="form-control" style="width:200px; display: inline-block;" placeholder="{{parseClassName(field.type)}}">
</div>
<div ng-show={{field.isEnum}}>
<p ng-show={{field.isRequired}}>{{field.name}}*: </p>
<p ng-show={{!field.isRequired}}>{{field.name}}: </p>
<select ng-model="createChildResource[field.name]" class="form-control" style="width:auto; display: inline-block;">
<option></option>
<option ng-repeat="enumValue in field.enumValues" label={{enumValue.name}}>{{enumValue.ordinal}}</option>
</select>
</div>
</div>
<div class="preview">
<p>Preview: </p>
<textarea style="height:350px; width:550px; overflow:scroll;">{{createChildResource | json}}</textarea >
</div>
The output is the following:
But if I try to add a ngModel to a textarea element to be able to edit this values in place like this:
<div class="preview">
<p>Preview: </p>
<textarea ng-model="createChildResource" style="height:350px; width:550px; overflow:scroll;">{{createChildResource | json}}</textarea>
</div>
then the output is the following:
In both cases I can't edit my model in a textarea element.
How can this be achieved? I'd like to be able to display and edit my model inplace like in this example with a slight difference: editable-textarea="user.description" should be editable-textarea="user".
I finally understand what you are trying to achieve. On the left you have a bunch of inputs and on the right (bottom), you have a textarea that arranges the inputs as properties of one object and displays them formatted as an object.
Your requirements is to allow user to edit the property values in the textarea and thus update the corresponding property value in the input.
First, as commented, convert the object to a string and then show it inside the textarea.
Next, since you need to react and update the input fields when the textarea is updated, you need to watch the value of the textarea and update the original object (the one that was converted to string).
Using an example here since your code is too complex to understand, let us say that you have the object containerObject as follows:
$scope.containerObject = {
property_1: "Hello",
property_2: "World"
};
Your inputs then make use of these properties:
<input ng-model="containerObject.property_1">
<input ng-model="containerObject.property_2">
Now, you wish to display this inside your textarea - you will first convert the object to string and display it as follows:
$scope.getObjectAsText = function () {
$scope.textAreaModel = JSON.stringify($scope.containerObject);
};
And your textarea markup will look like:
<textarea ng-model="textAreaModel"></textarea>
Each time the value in the input textboxes change, the textarea also gets updated.
Now, for the other way around. When you change the textarea, to have the input textboxes get updated, you need to watch the string model (and NOT the object model):
$scope.$watch('textAreaModel', function () {
try {
$scope.containerObject = JSON.parse($scope.textAreaModel);
} catch(exp) {
//Exception handler
};
});
You need to have the try...catch exception handler block because the user may accidentally change the contents such that on converting back to object, the result is not a suitable object (invalid property or invalid syntax).
As long as only the property value is changed, the input values will get updated correctly.
You can also wrap it into directive like below, or check the jsfiddler
Html
<div ng-app="app" ng-controller='userCtrl' >
<textarea obj-edit obj="user" rows='10'></textarea>
<p ng-bind='user.name'></p>
</div>
javascript
var app = angular.module("app", []);
app.controller('userCtrl', function($scope) {
$scope.user= {name: 'ron', ocupation: 'coder'};
});
app.directive('objEdit', function() {
return {
restrict: 'A',
scope: {
obj:'=obj'
},
link: function(scope, element, attrs) {
element.text(JSON.stringify(scope.obj, undefined, 2));
element.change(function(e) {
console.log(e.currentTarget.value);
scope.$apply(function() {
scope.obj = JSON.parse(e.currentTarget.value);
});
console.log(scope.obj);
})
}
}
})
Ron's answer is great.
Here is code that uses ngModel validation
HTML
<form name="text">
<textarea obj-edit ng-model="ctrl.json" name="json" rows="25" ng-model-options="{ debounce: 300 }"></textarea>
<div class="alert alert-danger" role="alert" ng-show="text.json.$error.json">
Error input
</div>
</form>
Javascript
app.directive('objEdit', function() {
return {
restrict: 'A',
require: "ngModel",
link: function(scope, element, attrs, ctrl) {
ctrl.$formatters.push(function formatter(value) {
return JSON.stringify(value, undefined, 2);
});
ctrl.$parsers.push(function(value) {
try {
var result = JSON.parse(value);
ctrl.$setValidity('json', true);
return result;
} catch (e) {
ctrl.$setValidity('json', false);
return undefined;
}
});
}
}});