I have created a angular dart component "Range" that a can be used in a form.
the form is a component as well
In my code I bind the value return by the component in the form but after renaming things it seems like the parameter given to #NgTwoWay(param), in my case #NgTwoWay("v1") is not doing anything it's still mandatory though.
Here is my code:
my_form.dart
library my_form;
import "package:angular/angular.dart";
#Component(selector: "my-form", templateUrl: "my_form.html", exportExpressions: const ["submit"])
class DateFormComponent {
#NgOneWay("random")
bool random;
#NgTwoWay("v1")
String years = "eee";
submit() {
print(random);
print(years);
}
}
class DateFormModule extends Module {
DateFormModule() {
bind(DateFormComponent);
}
}
my_form.html
<form>
<range name="years" value="years"></range>
<div>
<label>Random:</label> <input type="checkbox" ng-model="random">
</div>
<div>
<input type="submit" value="Go !" ng-click="submit()">
</div>
</form>
range.dart
import "package:angular/angular.dart";
#Component(selector: "range", templateUrl: "range.html")
class RangeComponent {
#NgAttr("name")
String name;
#NgTwoWay("value")
String value;
#NgOneWay("range_begin")
String range_begin;
#NgOneWay("range_end")
String range_end;
List<String> ranges = [];
addRange() {
ranges.add("$range_begin-$range_end");
range_begin = "";
range_end = "";
value = ranges.reduce((begin, item) {
return begin += ",$item";
});
}
info() {
print(range_begin);
print(range_end);
print(ranges);
print(value);
}
}
class RangeComponentModule extends Module {
RangeComponentModule() {
bind(RangeComponent);
}
}
range.html
<div>
<label>{{name}}:</label> <input type="text" placeholder="begin"
size="8" ng-model="range_begin"> <input type="text"
placeholder="end" size="8" ng-model="range_end"> <input
type="submit" value="add" ng-click="addRange()"> <input
type="submit" value="info" ng-click="info()">
</div>
I thought that parameter had to bind a DOM attribute with a property of an instance ?
You need these attributes to bind the HTML-attribute of your custom element (component) to a field of your components class.
<body ng-app>
<my-component someattrib="somevalue"></my-component>
when you MyComponent class has a field
#NgAttr('someattrib')
String someField;
then 'someField' will be initialized with 'somevalue'.
You don't need such an attribute for each binding only for binding to attributes.
Related
In ASP.NET i have the following
public class TestController : Controller
{
public IActionResult Index()
{
return View(new MyModel()
{
Activities = new Activity[]
{
new Activity(){ },
new Activity(){ }
}
});
}
}
public class MyModel
{
public IList<Activity> Activities { get; set; }
}
public class Activity
{
public bool IsActive { get; set; }
}
cshtml
#model Metatasker.Integration.UI.Controllers.MyModel
<form id="myform">
#for (int i = 0; i < Model.Activities.Count; i++)
{
#Html.CheckBoxFor(x => x.Activities[i].IsActive)
}
</form>
<button id="btn">Click Me</button>
<script type="text/javascript">
$(function () {
function validate() {
var kendoValidator = $('#myform').kendoValidator().data("kendoValidator");
return kendoValidator.validate();
}
$("#btn").click(function () {
alert(validate());
})
})
</script>
I am using Kendo's Validate method to validate form. In code above when i have multiple CheckBoxes The validate() method always returns false. If i have single check box then it works.
I have jsfiddle demo. The html in jsfiddle is a rendered Razor view.
DEMO
Try the following snippet.
<form id="form1">
<!-- Kendo UI Checkbox -->
<input type="checkbox" id="checkboxMale" name="Gender" required />
<label for="checkbox">Male</label>
<span class="k-invalid-msg" data-for="Gender"></span>
<input type="checkbox" id="checkboxFemale" name="Gender" required />
<label for="checkbox">Female</label>
<span class="k-invalid-msg" data-for="Gender"></span>
<button>Validate</button>
</form>
<script>
$(document).ready(function() {
var validator = $("#form1").kendoValidator().data("kendoValidator");
});
</script>
You will notice that the validator treats only true values as inputs which are filled, else it serves up the required validation message. Each check box is validated individually.
So, I suggest using a custom rule.
<form id="myform">
<ul validationMessage="You must enter a gender">
<li>
<input id="activity1" name="activity" type="checkbox" value="activity1" />
<label for="activity1">Activity1</label>
</li>
<li>
<input id="activity2" name="activity" type="checkbox" value="activity2" />
<label for="activity2">Activity2</label>
</li>
</ul>
<button>Validate</button>
</form>
<script>
$("#myform").kendoValidator({
rules: {
customRule1: function(input) {
if (input.is("[name=activity]")) {
return $("[name='activity']:checked").length > 0;
}
}
},
messages: {
customRule1: "Atleast one activity should be selected."
}
});
</script>
There is also a demo which uses radio buttons, which you can refer to.
I'm trying to pass some data to my MVC controller from AngularJS but the Customer object is always null on the MVC controller. What am I missing?
Angular
$scope.new = {};
$scope.AddCustomer = function () {
$http.post('/Customer/SaveCustomer', $scope.new).success(function () {
});
}
HTML
<input class="form-control" type="text" placeholder="CustomerID" ng-model="new.c.CustomerID" />
<input class="form-control" type="text" placeholder="CompanyName" ng-model="new.c.CompanyName" />
<button type="button" class="btn btn-primary" ng-click="AddCustomer()">Save</button>
C#
[HttpPost]
public void SaveCustomer(Customer customer)
{
....
}
public class Customer
{
public string CustomerID { get; set; }
public string CompanyName { get; set; }
}
Update your HTML like this :
Change new.c.CustomerID to new.CustomerID
<input class="form-control" type="text" placeholder="CustomerID" ng-model="new.CustomerID" />
<input class="form-control" type="text" placeholder="CompanyName" ng-model="new.CompanyName" />
Now this will work
$http.post('/Customer/SaveCustomer', $scope.new).success(function () {
});
First mind the camel case in javascript object
$scope.new = {
customerID: '',
companyName: ''
};
$scope.AddCustomer = function() {
$http.post('/Customer/SaveCustomer', $scope.new).success(function() {});
<!--check the changes in ng-model-->
<input class="form-control" type="text" placeholder="CustomerID" ng-model="new.customerID" />
<input class="form-control" type="text" placeholder="CompanyName" ng-model="new.companyName" />
<button type="button" class="btn btn-primary" ng-click="AddCustomer()">Save</button>
<!--Best of Luck-->
Your model seems to be
new = {
c : {
CustomerID : '',
CompanyName : ''
}
}
Which doesn't map to your Customer class. You should refer to new.CustomerID and new.CompanyName. Futhermore I would avoid using the new keyword as variable name.
I have created a form component. In that form component I also have a range component.
I was wondering how can I retrieve my value from my range component and more generally how can I interact with a component from outside it. (even if the goal is to encapsulate things)
I don't know if there are components like that somewhere but for now I just want to learn how it works. thanks !
Here is my code
index.html
<!DOCTYPE html>
<html ng-app>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>data_generator_front</title>
</head>
<body>
<my-form></my-form>
<div class="results"></div>
<script type="application/dart" src="index.dart"></script>
<script src="packages/browser/dart.js"></script>
</body>
</html>
index.dart
import "package:angular/angular.dart";
import "package:angular/application_factory.dart";
import "package:data_generator_front/component/my_form.dart";
import "package:data_generator_front/component/range.dart";
#Injectable()
class RootContext {
String myProperty = "jeahhhhhhhh";
void method1() {
print("method1");
}
}
main() {
applicationFactory()
.rootContextType(RootContext)
.addModule(new DateFormModule())
.addModule(new RangeComponentModule())
.run();
}
my_form.html
<form>
<range name="years" value="myProp"></range>
<div>
<label>Random:</label>
<input type="checkbox" ng-model="random">
</div>
<div>
<input type="submit" value="Go !">
</div>
</form>
my_form.dart
library my_form;
import "package:angular/angular.dart";
#Component(selector: "my-form", templateUrl: "my_form.html", exportExpressions: const ["submit"])
class DateFormComponent {
#NgOneWay("random")
bool random;
submit() {
print("hello");
}
}
class DateFormModule extends Module {
DateFormModule() {
bind(DateFormComponent);
}
}
range.dart
import "package:angular/angular.dart";
#Component(selector: "range", templateUrl: "range.html")
class RangeComponent {
#NgAttr("name")
String name;
#NgOneWay("range_begin")
String range_begin;
#NgOneWay("range_end")
String range_end;
List<String> ranges = [];
addRange() {
ranges.add("$range_begin-$range_end");
range_begin = "";
range_end = "";
}
info(){
print(range_begin);
print(range_end);
print(ranges);
print(ranges.reduce((begin, item){
return begin += ",$item";
}));
}
}
class RangeComponentModule extends Module {
RangeComponentModule() {
bind(RangeComponent);
}
}
range.html
<div>
<label>{{name}}:</label>
<input type="text" placeholder="begin" size="8" ng-model="range_begin">
<input type="text" placeholder="end" size="8" ng-model="range_end">
<input type="submit" value="add" ng-click="addRange()" >
<input type="submit" value="info" ng-click="info()" >
<input type="submit" value="value" ng-click="range()" >
</div>
I guess changing NgOneWay to NgTwoWay should do the trick so the value gets updated inside the component. To get the value outside of the component bind
<range name="years" value="{{myProp}}"></range>
and create a field in your my-form component.
#NgTwoWay('myProp')
var myProp;
Alternatively you can implement ScopeAware to get the scope and then use scope.emit, scope.broadcast, scope.on... to send the data as event on submit to send it across the DOM not just to the immediate parent/child
almost :) but it's only works one way
I initialize the property in my_form.dart then the my_form.html has the value binded and finally the range component can use the value at init time.
but when I change the code inside the component the value is not binded anymore with the my_form.dart
here is the code
range.html didn't change
my_form.dart
library my_form;
import "package:angular/angular.dart";
#Component(selector: "my-form", templateUrl: "my_form.html", exportExpressions: const ["submit"])
class DateFormComponent {
#NgOneWay("random")
bool random;
#NgTwoWay("v1")
String v1 = "eee";
submit() {
print(random);
print(v1);
}
}
class DateFormModule extends Module {
DateFormModule() {
bind(DateFormComponent);
}
}
my_form.html
<form>
<range name="years" value="{{v1}}"></range>
<div>
<label>Random:</label>
<input type="checkbox" ng-model="random">
</div>
<div>
<input type="submit" value="Go !" ng-click="submit()">
</div>
</form>
range.dart
import "package:angular/angular.dart";
#Component(selector: "range", templateUrl: "range.html")
class RangeComponent {
#NgAttr("name")
String name;
#NgAttr("value")
String value;
#NgOneWay("range_begin")
String range_begin;
#NgOneWay("range_end")
String range_end;
List<String> ranges = [];
addRange() {
ranges.add("$range_begin-$range_end");
range_begin = "";
range_end = "";
value = ranges.reduce((begin, item){
return begin += ",$item";
});
}
info(){
print(range_begin);
print(range_end);
print(ranges);
print(value);
}
}
class RangeComponentModule extends Module {
RangeComponentModule() {
bind(RangeComponent);
}
}
thanks for helping anyway :)
I'm can't find any doc that explains how to manipulates forms in Angular Dart.
I've got the following code in my_component.html:
<form name="form" ng-submit="comp.save()">
<input type="text" required ng-model="comp.user.firstname">
<input type="text" required ng-model="comp.user.lastname">
<button ng-disabled="form.invalid">Save</button>
</form>
And the following one in my_component.dart:
#NgComponent(
selector : 'my-component',
templateUrl : 'my_component.html',
publishAs : 'comp'
)
class MyComponent {
#NgTwoWay('user')
User user;
#NgTwoWay('form')
NgForm form;
MyComponent() {};
void save() {
print(form);
}
}
The validation works well, but when clicking on the button, the print(form) statement always prints null.
Any idea?
Thanks
I guess this is what you want:
class MyComponent {
#NgTwoWay('user')
User user = new User();
Scope scope;
MyComponent(this.scope) {}
void save() {
var form = (scope.context['form'] as NgForm);
print(form.invalid);
}
}
I need to validate a group of checkboxes using MVC3 unobtrusive validation. how would i do it? I found this and tried it, but it doesn't work.
$(function(){
$.validator.addMethod('cb_selectone', function(value,element){
if(element.length>0){
for(var i=0;i<element.length;i++){
if($(element[i]).val('checked')) return true;
}
return false;
}
return false;
}, 'Please select at least one option');
$('#main').validate({rules:{Services:"cb_selectone"}});
...
My Html:
<input type="checkbox" class="checkbox" name="Services" value="1" />
<input type="checkbox" class="checkbox" name="Services" value="2" />
<input type="checkbox" class="checkbox" name="Services" value="3" />
It would be best if someone provided a complete solution with server side + client side validation (of course using MVC3 unobtrusive validation).
Thanks
Ok, figured it out:
for server validation:
using data annotations (required will do it)
like so in my view model:
[Required(ErrorMessageResourceName = "fld_Service_val_Required_lbl", ErrorMessageResourceType = typeof(Resources.Service.Controllers.Firm))]
public ICollection<int> Services { get; set; }
for client validation in my html i added a class to my input checkboxes:
<input type="checkbox" class="checkbox required-checkbox" name="Services" value="1" />
<input type="checkbox" class="checkbox required-checkbox" name="Services" value="2" />
<input type="checkbox" class="checkbox required-checkbox" name="Services" value="3" />
and also:
$(function(){
$.validator.addMethod('required_group', function(value, element) {
var $module = $(element).parents('form');
return $module.find('input.checkbox:checked').length;
}, 'Select at least one Service please');
$.validator.addClassRules('required-checkbox', { 'required_group' : true });
..
not sure if this is the best solution but it works :). if someone knows a better please post.
This works - validates appropriately on submit, and hides/displays the validation message if a checkbox is subsequently checked or unchecked with minimal overhead (only gets hit once per validation cycle).
JavaScript:
(function ($) {
//functions from unobtrusive:
function setValidationValues(options, ruleName, value) {
options.rules[ruleName] = value;
if (options.message) {
options.messages[ruleName] = options.message;
}
}
var formEls;
function getUniqueFormId(form) {
if (typeof(formEls==='undefined')) {
formEls = document.getElementsByTagName('form');
}
return 'form' + Array.prototype.indexOf.call(formEls, form);
}
//from jQuery validation
function findByName(name, form) {
// select by name and filter by form for performance over form.find("[name=...]")
return $(document.getElementsByName(name)).map(function (index, element) {
return element.form == form && element.name == name && element || null;
});
}
//-------------------------
$.validator.addMethod('requiredgroup', function (value, element, params) {
for (var i = 0; i < params.length; i++) {
if (params[i].checked) { return true; }
}
return false;
});
valGroups = [];
$.validator.unobtrusive.adapters.add('requiredgroup', function (options) {
var groupName = options.element.name,
uniqueGroup = getUniqueFormId(options.form) + groupName;
if (!valGroups[uniqueGroup]) {
valGroups[uniqueGroup] = findByName(groupName, options.form);
}
//jQuery Validation Plugin 1.9.0 only ever validates first chekcbox in a list
//could probably work around setting this for every element:
setValidationValues(options, 'requiredgroup', valGroups[uniqueGroup]);
});
} (jQuery));
of course the elements must have a data-val-requiredgroup attribute. The following MVC code (as part of a helper) will add the appropriate annotations:
var metaData = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);
string name = ExpressionHelper.GetExpressionText(expression);
var baseAttr = htmlHelper.GetUnobtrusiveValidationAttributes(name, metaData);
baseAttr.Add("name", name);
baseAttr.Add("type", "checkbox");
if (metaData.IsRequired)
{
baseAttr.Add("data-val-requiredgroup", baseAttr["data-val-required"]);
baseAttr.Remove("data-val-required");
Because it looks for the Required attribute, server side validation is handled by the existing framework.