How show diff. HTML based on property in angularjs? - javascript

I have a collection of objects that are of types: text, selectoptions and multiselectoptions. I need to display them as editable inputs based on their type.
For example, a text object:
<input type="text" name="caption" value="{{option.value}}" />
A selectoption/multiselectoptions:
<div ng-repeat="value in option.values">
<input type="text" name="{{option.id}}[value][{{value.id}}]" value="{{value.value}}" />
<input type="text" name="{{option.id}}[caption][{{value.id}}]" value="{{value.caption}}" />
</div>
Is this the correct way to do this? Is there a better way to represent it?
Example of the JSON objects:
FORM: {
options: [
{
type: "select",
values: [
{
value: 0,
caption: "Some option"
},
{
value: 1,
caption: "Some other option"
}
]
},
{
type: "text",
caption: "Some text item"
}
]
}

You could use ng-if to display the correct form element based on your model. Here is an example in plunker based on your code.
<form novalidate class="simple-form">
<div ng-repeat="field in FORM.options">
<input type="text" ng-model='field.caption' ng-if="field.type == 'text'" /><br />
<div ng-if="field.type != 'text'">
<div ng-repeat="value in field.values">
Option: <input type="text" name="{{option.id}}[value][{{value.id}}]" value="{{value.value}}" /><br/>
Caption: <input type="text" name="{{option.id}}[caption][{{value.id}}]" value="{{value.caption}}" /><br/>
</div>
</div>
</div>
<button ng-click="submit()">Save</button>
</form>
I check the type field.type and display different HTML in the main ng-repeat.
The app assign your model to FORM:
$scope.FORM = {
options: [
{
type: "select",
values: [
{
value: 0,
caption: "Some option"
},
{
value: 1,
caption: "Some other option"
}
]
},
{
type: "text",
caption: "Some text item"
}
]
};
I also added a submit button that display the model in the Javascript console, so you can see that the data is being updated when you change the values:
<button ng-click="submit()">Save</button>

Try ng-switch which will switch to corresponding HTML based on the type from the JSON.
<div ng-repeat="opt in FORM.options" ng-switch on="opt.type">
<select ng-switch-when="select">
<option ng-repeat="val in opt.values" value='{{val.value}}'>{{val.caption}}</option>
</select>
<input type="text" ng-model="opt.caption" ng-switch-when="text"/>
</div>
Add more MultiSelect types with ng-switch-when = "multiselect". If the type is not specified, set a ng-switch-default to default html.
Working Plunker

Related

Make diffrent V-MODEL on every index that i generate

How can I have different V-MODEL on every object that i generate
I am trying to make an sample cupcake website that can generate multiple forms in one submit.
But when I generate 2 field, the inputs of the 2 generated field bound by each other inputs.
This is the code I am trying to generate:
<template>
<div>
<button #click="cupcakes.push(def)">Add Cup Cake</button>
<div v-for="(cupcake, index) in cupcakes" :key="index">
<input type="text" v-model="cupcakes[index].name">
<input type="text" v-model="cupcakes[index].description">
<input type="text" v-model="cupcakes[index].type">
<input type="text" v-model="cupcakes[index].prize">
<input type="text" v-model="cupcakes[index].color">
</div>
<button #click="onSubmit">Create Cupcate</button>
</div>
</template>
<script>
export default {
data() {
return {
cupcakes: [],
def: {
name: '',
description: 'Originals',
type: 'small',
prize: 500,
color: 'color'
}
}
},
methods: {
onSubmit() {
console.log(this.cupcakes);
}
}
}
</script>
I tried to do other things but it doesn't work.
How can I dis bind the 2 field and when I submit it will take the inputs that I type or input.
You are pushing n times the same objet (def) into your cupcakes Array. def is a reference to an object. So when you update cupcakes[n], you are just updating the def values.
What you need to do is send a copy of that object into the cupcakes object:
<button #click="cupcakes.push(JSON.parse(JSON.stringify(def)))">Add Cup Cake</button>
I think a better pattern would be to make a method that returns you a new cupcake:
<template>
<div>
<button #click="cupcakes.push(getNewCupcake())">Add Cup Cake</button>
<div v-for="(cupcake, index) in cupcakes" :key="index">
<input type="text" v-model="cupcakes[index].name">
<input type="text" v-model="cupcakes[index].description">
<input type="text" v-model="cupcakes[index].type">
<input type="text" v-model="cupcakes[index].prize">
<input type="text" v-model="cupcakes[index].color">
</div>
<button #click="onSubmit">Create Cupcate</button>
</div>
</template>
<script>
export default {
data() {
return {
cupcakes: []
};
},
methods: {
onSubmit() {
console.log(this.cupcakes);
},
getNewCupcake() {
return {
name: "",
description: "Originals",
type: "small",
prize: 500,
color: "color"
}
}
}
};
</script>

JSRender loop through fields

I try to create a (for me) complex template (form). My data is like this
var fields = [
{ name: "field1", type: "text", label: "Name" },
{ name: "field2", type: "text", label: "Address" },
{ name: "field3", type: "date", label: "Birth date" }
];
My template (part of it) is like this:
<form id="EditForm">
<table width="100%" border="0">
<tr>
{{for}}
<td>
<div class="form-group">
<label for={{>name}}>{{>label}}</label>
<input type={{>type}} class="form-control" id={{>name}}>
</div>
</td>
{{/for}}
... etc...
I tried some different things but it is looks like it is not looping all my field.
I use jsREnder like this:
<div id="test"></div>
<script type="text/javascript">
$("#test").html(
$("#UpdateTemplate").render(fields, true)
);
</script>
I changed my code. It is working now. Just had to do a "for" without adding a field

Set ng-model dynamically without populating the textbox

I have the following ng-repeat
<div ng-repeat="selectedColumn in SelectedListItems" class="form-group">
<label class="control-label col-lg-4">{{selectedColumn.column}}</label>
<div class="col-lg-8">
<input ng-model="selectedColumn.column" type="text" value="" class="form-control" />
</div>
</div>
The SelectedListItems is:
$scope.SelectedListItems = [
{ column: 'Description' },
{ column: 'Colour' },
{ column: 'KW/PS' },
{ column: 'Chilometri x 1000 km' },
{ column: 'Reg.' },
{ column: 'Equipment' },
{ column: 'No. PJVA' },
{ column: 'Price' }
];
For each of those column I want a new textbox. Also, I wanted to set an ng-model dynamically for every textbox so that I can use the values that are typed in it.
Now I have two issues:
The textbox is populated with the column value and also the ng-model is selectedColumn.column in browser when I inspect the textbox, so I can't seem to understand how will I get the values from those textboxes.
you can do the following .
<div ng-repeat="selectedColumn in SelectedListItems" class="form-group">
<label class="control-label col-lg-4">{{selectedColumn.column}}</label>
<div class="col-lg-8">
<input ng-model="selectedColumn.textInput" type="text" value="" class="form-control" />
</div>
</div>
and can access value like this.
example for description.
$scope.SelectedListItems[0].textInput;
You can add a new property for every item in the array and store the value there.
$scope.SelectedListItems = [
{ columnName: 'Description', columnValue:'' },
{ columnName: 'Colour', columnValue:'' }
];
HTML
<div ng-repeat="selectedColumn in SelectedListItems" class="form-group">
<label class="control-label col-lg-4">{{selectedColumn.columnName}}</label>
<div class="col-lg-8">
<input ng-model="selectedColumn.columnValue" type="text" value="" class="form-control" />
</div>
</div>

how to validate element is angular js?

I make a view from json object. I am able to make take now I need to valid element on keyup event and blur event. So I googled it and find this tutorial
http://scotch.io/tutorials/javascript/angularjs-form-validation
I try to implement this in my demo, but when I used this:
<p ng-show="userForm.name.$invalid && !userForm.name.$pristine"
class="help-block">`Your name is required.</p>
This break my view can you please tell me how to validate thing in angular if there is no form?
Here is my plunker: http://plnkr.co/edit/we1QHuDuCOOR4tDAk6yv?p=preview
<script>
function Controller($scope) {
$scope.outputs = {};
$scope.inputs = [{
type: "email",
name: "email",
required:true
}, {
type: "text",
name: "name",
}, {
type: "number",
name: "phonenumber",
}, {
type: "checkbox",
name: "whant to check",
},
{
type: "url",
name: "server Url",
}];
}
</script>
A solution is to use ng-form like
<div ng-switch="input.type" ng-form="myfrm">
<div ng-switch-when="text">
<input type="text" ng-model="outputs[input.name]"/>
</div>
<div ng-switch-when="email">
<input type="email" ng-model="outputs[input.name]" name="input" ng-required="input.required">
<span ng-if="myfrm.input.$invalid">Please enter a valid email</span>
</div>
<div ng-switch-when="number">
<input type="number" ng-model="outputs[input.name]"/>
</div>
<div ng-switch-when="url">
<input type="number" ng-model="outputs[input.name]"/>
</div>
<div ng-switch-when="checkbox">
<input type="checkbox" ng-model="outputs[input.name]" ng-checked="outputs[input.name]" value="outputs[input.name]"/>
</div>
</div>
Demo: Plunker

Multiple inputs in a Bootbox

How can I have 2 inputs instead of just one in Bootstrap's Bootbox?
I need to receive 2 values in a modal dialog.
Actually, there is a simpler way which doesn't require you to modify bootbox code.
The string you pass at the bootbox creation doesn't have to be only text: it can also be html code. That means you can include pretty much everything in the box.
To put a custom form in a bootbox, you can then create it as follow :
bootbox.confirm("<form id='infos' action=''>\
First name:<input type='text' name='first_name' /><br/>\
Last name:<input type='text' name='last_name' />\
</form>", function(result) {
if(result)
$('#infos').submit();
});
I just made function for that, check it out - here
Usage example
bootbox.form({
title: 'User details',
fields: {
name: {
label: 'Name',
value: 'John Connor',
type: 'text'
},
email: {
label: 'E-mail',
type: 'email',
value: 'johnconnor#skynet.com'
},
type: {
label: 'Type',
type: 'select',
options: [
{value: 1, text: 'Human'},
{value: 2, text: 'Robot'}
]
},
alive: {
label: 'Is alive',
type: 'checkbox',
value: true
},
loves: {
label: 'Loves',
type: 'checkbox',
value: ['bike','mom','vg'],
options: [
{value: 'bike', text: 'Motorbike'},
{value: 'mom', text: 'His mom'},
{value: 'vg', text: 'Video games'},
{value: 'kill', text: 'Killing people'}
]
},
passwd: {
label: 'Password',
type: 'password'
},
desc: {
label: 'Description',
type: 'textarea'
}
},
callback: function (values) {
console.log(values)
}
})
For me, this is the cleanest way to do it :
var form = $('<form><input name="usernameInput"/></form>');
bootbox.alert(form,function(){
var username = form.find('input[name=usernameInput]').val();
console.log(username);
});
Create hidden div with form in HTML and inject this html to bootbox message. Snippet below.
var buttonClick = function() {
var bootboxHtml = $('#js-exampleDiv').html().replace('js-exampleForm', 'js-bootboxForm');
bootbox.confirm(bootboxHtml, function(result) {
console.log($('#ex1', '.js-bootboxForm').val());
console.log($('#ex2', '.js-bootboxForm').val());
});
};
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js"></script>
<div id="js-exampleDiv" hidden>
<form class="js-exampleForm">
<div class="col-sm-12">
<input placeholder="Example placeholder 1" id="ex1" />
</div>
<div class="col-sm-12">
<input placeholder="Example placeholder 2" id="ex2" />
</div>
</form>
</div>
<button onclick="buttonClick();">
Open bootbox confirm dialog.
</button>
You have to write your own function which will load dialog function from bootbox.
The easiest way is to copy prompt function from source: https://raw.github.com/makeusabrew/bootbox/v3.2.0/bootbox.js
and change this part for adding new input (or whatever you need)
// let's keep a reference to the form object for later
var form = $("<form></form>");
form.append("<input autocomplete=off type=text value='" + defaultVal + "' />");
and this part for getting result:
var confirmCallback = function() {
if (typeof cb === 'function') {
return cb(form.find("input[type=text]").val());
}
};
Here is a basic example for what you need (using knockout)
<button data-bind="click: select">Button</button>
<script type="text/html" id="add-template">
<div style="display:none">
<input data-bind='value: name' placeholder="Name">
</div>
</script>
var viewModel = function () {
var self = this;
self.name = ko.observable();
self.select = function () {
var messageTemplate = $($("#add-template").html());
ko.applyBindings(self, messageTemplate.get(0));
messageTemplate.show();
bootbox.confirm({
title: "Add new",
message: messageTemplate,
callback: function (value) {
// do something
}
});
}
}
ko.applyBindings(new viewModel());
Just add as many fields and bind them in the view model
http://jsfiddle.net/6vb7e224/2/
haradwaith Has the best solution for posting form data from a bootbox. Because it works, it's simple and because he demonstrates how to Actually Submit the Form. His solution:
bootbox.confirm("<form id='infos' action=''>\
First name:<input type='text' name='first_name' /><br/>\
Last name:<input type='text' name='last_name' />\
</form>", function(result) {
if(result)
$('#infos').submit();
});
Moving the <form> tag outside of the bootbox object allows the use of PHP when posting to self and to include hidden inputs without all the clutter.
<form method="post" action="<?php echo htmlspecialchars($_SERVER["PHP_SELF"]);?>" id="infos">
<input type=hidden form="infos" name="created" value="<?php echo date("Y-m-d H:i:s"); ?>" />
</form>
Now you can check for $_POST['created']
<?php
if(isset($_POST['created'])){
echo "Timestamp: ".$_POST['created']; // great things happen here
}
?>
You can create the form anywhere in the body tag, it won't display because the inputs are hidden.
Hope that helps!
I know this question is pretty old now, but this is the way I've done it. I think this way is great for larger forms as putting all of the HTML in JavaScript can get ugly pretty quick.
This example uses Bootstrap but the idea is the same. Create a hidden form in HTML and then select it using JavaScript or JQuery.
HTML:
<div id="hiddenForm" class="hidden">
<form id="myForm" class="form-horizontal">
<div class="form-group">
<label class="control-label col-sm-2">First Name</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="FirstName" />
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">Last Name</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="LastName" />
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">City</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="City" />
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">State</label>
<div class="col-sm-10">
<input type="text" class="form-control" name="State" />
</div>
</div>
</form>
</div>
JavaScript Version:
var form = document.getElementById("hiddenForm").innerHTML;
bootbox.confirm({
message: form,
callback: function (result) {
// do something
}
});
JQuery Version:
var form = $("#hiddenForm").html();
bootbox.confirm({
message: form,
callback: function (result) {
// do something
}
});
Note:
When you try to serialize the form for posting, you'll have to make sure you are actually targeting the right form. $("#myForm").serialize() will most likely not work as it will grab the actual HTML form that you built earlier. So instead, you should do something like $(".bootbox-body #myForm").serialize() to get the current form's values.

Categories