Formly bootstrap. How do I show label with html? - angular-ui-bootstrap

I am using angularjs formly. Bootstrap template. I am looking a way to show html code I label. Now they are escaped when display
Here is the formly fields
vm.fields = [
{
key: 'awesome',
type: 'checkbox',
templateOptions: { label: 'this is a test' }
},
{
key: 'exampleDirective',
template: '<div example-directive></div>',
templateOptions: {
label: 'Example Directive',
}
}
];
I expected the A tag in "this is a test" can render properly.

In my case in with a textarea but i hope this help you to made a similar formly type with checkbox that can use html in label
I create a new type caled textareaHtml, it just extend 'textarea' and use this wrapper 'labelHtml' that load html with
'<span ng-bind-html="to.label" ></span>',
here the code
app.run(function(formlyConfig ) {
formlyConfig.setWrapper(
{
name: 'labelHtml',
template: [
'<div>',
'<label for="{{id}}" class="control-label {{to.labelSrOnly ? \'sr-only\' : \'\'}}" ng-if="to.label">',
'<span ng-bind-html="to.label" ></span>',
'{{to.required ? \'*\' : \'\'}}',
'</label>',
'<formly-transclude></formly-transclude>',
'</div>'
].join(' ')
}
);
formlyConfig.setType({
name: 'textareaHtml',
extends: 'textarea',
wrapper: ['labelHtml', 'bootstrapHasError']
});
});

I fixed the #imaginabit answer:
<script type="text/ng-template" id="checkboximp.html">
<div class="checkbox">
<label>
<input type="checkbox"
class="formly-field-checkbox"
ng-model="model[options.key]">
{{to.required ? '*' : ''}}
<div ng-bind-html="to.label"> </div>
</label>
</div>
</script>
/* global angular */
(function() {
'use strict';
var app = angular.module('formlyExample', ['formly', 'formlyBootstrap', 'ngSanitize'], function config(formlyConfigProvider) {
// set templates here
formlyConfigProvider.setType({
name: 'checkboxHtml',
extends: 'checkbox',
templateUrl: 'checkboximp.html',
wrapper: ['bootstrapHasError']
});
});
app.controller('MainCtrl', function MainCtrl(formlyVersion) {
var vm = this;
// funcation assignment
vm.onSubmit = onSubmit;
// variable assignment
vm.author = { // optionally fill in your info below :-)
name: 'Kent C. Dodds',
url: 'https://twitter.com/kentcdodds' // a link to your twitter/github/blog/whatever
};
vm.exampleTitle = 'Introduction';
vm.env = {
angularVersion: angular.version.full,
formlyVersion: formlyVersion
};
vm.model = {
awesome: true
};
vm.options = {
formState: {
awesomeIsForced: false
}
};
vm.fields = [
{
key: 'awesome',
type: 'checkbox',
templateOptions: { label: 'this is a test' }
},
{
key: 'awesome2',
type: 'checkboxHtml',
templateOptions: { label: 'this is a from j. lennon' }
}
];
// function definition
function onSubmit() {
alert(JSON.stringify(vm.model), null, 2);
}
});
})();
http://jsbin.com/dunuyakiwe/2/edit?html,js,output
Just two observations:
It's necessary to have angular sanitize library, and that would make the template work fine (ng-bind-html directive).
The default checkbox formly template has an embedded label in the component, so is not possible to use that out of the box, that's why it's simpler to create our own type.

Related

C# razor select2 disable

Is there a way I can set this select2 to be disable read-only if there is a value in option.AgentName? I have add the selectElement.select2 method is there anything I can add to the callback?
Is this the correct way to do this? using self.entry.Agent.AgentName != ""?
View
<div class="form-group sentence-part-container sentence-part ng-scope ui-draggable sentence-part-entry-agent sentence-part-with-select2-single" [class.has-errors]="entry.IsInvalid && entry.IsTouched">
<div class="sentence-part-values">
<div class="sentence-part-values-select2-single">
<select class="form-control" style="width: 300px" [(ngModel)]="entry.Agent.VersionKey">
<option *ngFor="let option of agents" [value]="option.VersionKey">{{option.AgentName}}</option>
</select>
</div>
</div>
</div>
ts file
$selectElement.select2({
initSelection: function(element, callback) {
console.log(self.entry.Agent.AgentName);
if (self.entry.Agent.AgentName != "")
{
console.log('disabled');
$selectElement.prop('disabled', true);
}
callback({ id: self.entry.Agent.VersionKey, text: self.entry.Agent.AgentName });
},
placeholder: "Select an agent"
})
.on("change", (e) => {
self.ngZone.run(() => {
self.entry.Agent.VersionKey = $selectElement.val();
self.entry.AgentVersionKey = self.entry.Agent.VersionKey;
let regimenEntryAgent = this.getRegimenEntryAgentByVersionKey(self.entry.Agent.VersionKey);
if (regimenEntryAgent) {
self.entry.Agent.AgentId = regimenEntryAgent.AgentId;
}
self.onSentenceChange(null);
});
})
.on("select2:close", () => {
self.entry.IsTouched = true;
this.validate();
});
You might try to apply some logic in newData.push() method of Select2.
ajax: {
url: '/DemoController/DemoAction',
dataType: 'json',
delay: 250,
data: function (params) {
return {
query: params.term, //search term
page: params.page
};
},
processResults: function (data, page) {
var newData = [];
$.each(data, function (index, item) {
// apply some logic to the corresponding item here
if(item.AgentName == "x"){
}
newData.push({
//id part present in data
id: item.Id,
//string to be displayed
text: item.AgentName
});
});
return { results: newData };
},
cache: true
},
Update:
It is recommended that you declare your configuration options by passing in an object when initializing Select2. However, you may also define your configuration options by using the HTML5 data-* attributes.
For the other Select2 options look Options.

give default value to md-autocomplete

How to pass default value in md-autocomplete?
Image 1 : HTML code
Image 2 : JS code
Image 3 : Output
As you can see, I am not getting any default country as output. Is there any way to do that?
Assign yr SearchText the default value & selectedItem the object.
$scope.local ={
...
searchText : 'Default Value',
selectedItem : 'Default object'
...
}
I write small codepen with autocomplete and default value.
What you must do:
Init main model.
Define model field, used in autocomplete md-selected-item property.
Define callback for loading autocomplete items.
Before save main model extract id (or other field) from associated field.
Main error in your code here:
$scope.local = {
...
selectedItem: 1, // Must be object, but not integer
...
}
(function(A) {
"use strict";
var app = A.module('app', ['ngMaterial']);
function main(
$q,
$scope,
$timeout
) {
$timeout(function() {
$scope.user = {
firstname: "Maxim",
lastname: "Dunaevsky",
group: {
id: 1,
title: "Administrator"
}
};
}, 500);
$scope.loadGroups = function(filterText) {
var d = $q.defer(),
allItems = [{
id: 1,
title: 'Administrator'
}, {
id: 2,
title: 'Manager'
}, {
id: 3,
title: 'Moderator'
}, {
id: 4,
title: 'VIP-User'
}, {
id: 5,
title: 'Standard user'
}];
$timeout(function() {
var items = [];
A.forEach(allItems, function(item) {
if (item.title.indexOf(filterText) > -1) {
items.push(item);
}
});
d.resolve(items);
}, 1000);
return d.promise;
};
}
main.$inject = [
'$q',
'$scope',
'$timeout'
];
app.controller('Main', main);
}(this.angular));
<head>
<link href="https://cdnjs.cloudflare.com/ajax/libs/angular-material/0.11.0/angular-material.min.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular-aria.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.6/angular-animate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular-material/0.11.0/angular-material.min.js"></script>
</head>
<body ng-app="app" flex layout="column" layout-margin ng-controller="Main">
<md-content layout="column" class="md-whiteframe-z1" layout-margin>
<md-toolbar>
<div class="md-toolbar-tools">
<h3>Form</h3>
</div>
</md-toolbar>
<md-content class="md-whiteframe-z1">
<div class="md-padding">
<md-input-container>
<label for="firstname">First name</label>
<input type="text" name="firstname" ng-model="user.firstname" />
</md-input-container>
<md-input-container>
<label for="lastname">Last name</label>
<input type="text" name="lastname" ng-model="user.lastname" />
</md-input-container>
<md-autocomplete md-selected-item="user.group" md-items="item in loadGroups(filterText)" md-item-text="item.title" md-search-text="filterText">
<md-item-template>{{ item.title }}</md-item-template>
<md-not-found>No items.</md-not-found>
</md-autocomplete>
</div>
</md-content>
</md-content>
<md-content class="md-whiteframe-z1" layout-margin>
<md-toolbar>
<div class="md-toolbar-tools">
<h3>Model as JSON</h3>
</div>
</md-toolbar>
<md-content class="md-padding">
<p>
{{ user | json }}
</p>
</md-content>
</md-content>
</body>
I know this is an old question, but some people may benefit from my solution. I struggled with the problem of the model for the auto-complete being asynchronous and having my autocompletes as part of an ng-repeat. Many of the solutions to this problem found on the web have only a single auto complete and static data.
My solution was to add another directive to the autocomplete with a watch on the variable that I want to set as default for the auto complete.
in my template:
<md-autocomplete initscope='{{quote["Scope"+i]}}' ng-repeat='i in [1,2,3,4,5,6,7,8]'
class='m-1'
md-selected-item="ScopeSelected"
md-clear-button="true"
md-dropdown-position="top"
md-search-text="pScopeSearch"
md-selected-item-change='selectPScope(item.label,i)'
md-items="item in scopePSearch(pScopeSearch,i)"
md-item-text="item.label"
placeholder="Plowing Scope {{i}}"
md-min-length="3"
md-menu-class="autocomplete-custom-template"
>
then in my module:
Details.directive('initscope', function () {
return function (scope, element, attrs) {
scope.$watch(function (){
return attrs.initscope;
}, function (value, oldValue) {
//console.log(attrs.initscope)
if(oldValue=="" && value!="" && !scope.initialized){
//console.log(attrs.initscope);
var item = {id:0, order:0,label:attrs.initscope?attrs.initscope:"" }
scope.ScopeSelected = item;
scope.initialized = true;
}
});
};
});
this checks for changes to the quote["Scope"+i] (because initially it would be null) and creates an initial selected item and sets the autocompletes' selected item to that object. Then it sets an initialized value to true so that this never happens again.
I used timeout to do this.
$timeout(function() {
$scope.local = {selectedItem : 1}
}, 2000);

AngularJS and ui-grid interaction using $resource

I am brand new to angular JS and obviously to ui-grid as well. I got data to display in a grid using $resource and am trying to move to the next level by allowing editing and saving of rows etc.
I used Saving row data with AngularJS ui-grid $scope.saveRow as an example and created the Plunker http://plnkr.co/edit/Gj07SqU9uFIJlv1Ie6S5 to try it. But, for some reason I can't fathom, mine doesn't work and in fact it generates an exception at the line:
gridApi.rowEdit.on.saveRow(self, self.saveRow);
And I am at a total loss to understand why. I realize that the saveRow function is empty, but the goal at this stage is simply to get it called when the row has been edited.
Any help would be greatly appreciated.
The code of the Plunker follows:
(function() {
var app = angular.module('testGrid', ['ngResource', 'ui.grid', 'ui.grid.edit', 'ui.grid.rowEdit' /*, 'ui.grid.cellNav'*/ ]);
app.factory('Series', function($resource) {
return $resource('/api/series/:id', {
id: '#SeriesId'
});
});
var myData = [{
SeriesId: 1,
SeriesName: 'Series 1'
}, {
SeriesId: 2,
SeriesName: 'Series 2'
}];
app.directive('gridContent', function() {
var deleteTemplate = '<input type="button" value="Delete" ng-click="getExternalScopes().deleteRow(row)" />';
var commandheaderTemplate = '<input type="button" value="Add Series" ng-click="getExternalScopes().addNew()" />';
return {
restrict: 'E',
templateUrl: 'grid.html',
controllerAs: 'gridseries',
controller: function(Series) {
var self = this;
this.saveRow = function(rowEntity) {
i = 0;
};
this.gridOptions = {};
this.gridOptions.columnDefs = [{
name: 'SeriesId',
visible: false
}, {
name: 'SeriesName',
displayName: 'Name',
enableCellEdit: true
}, {
name: 'Command',
displayName: 'Command',
cellTemplate: deleteTemplate,
headerCellTemplate: commandheaderTemplate
}];
this.gridOptions.onRegisterApi = function(gridApi) {
self.gridApi = gridApi;
gridApi.rowEdit.on.saveRow(self, self.saveRow);
};
this.gridOptions.data = myData;
this.gridScope = {
deleteRow: function(row) {
var index = myData.indexOf(row.entity);
self.gridOptions.data.splice(index, 1);
},
addNew: function() {
self.gridOptions.data.push({
SeriesName: 'Add a name'
});
}
};
}
};
});
})();
I have no idea why the code didn't cut and paste properly but all the code is in the Plunker any way.
Thanks in advance.
I think the main problem here is that you're using a controller as syntax, rather than the $scope setup. Registering an event requires a $scope, as the event handler is then removed again upon the destroy event of that $scope.
A shorthand workaround is to use $rootScope instead, but this may over time give you a memory leak.
gridApi.rowEdit.on.saveRow($rootScope, self.saveRow);
Refer: http://plnkr.co/edit/Gj07SqU9uFIJlv1Ie6S5?p=preview
Since this code was also a bit old, I had to update to the new appScope arrangements rather than externalScope.

Why can't I bind input type "checkbox" in cellTemplate?

Here is my plunker example: http://plnkr.co/edit/Tc9FRHAEoQlOqy7sk1Ae?p=preview
What I'm trying to do:
Bind the checkbox html from field04 in my data to the cell using cellTemplate and still have access to its ng-click function.
Code in app.js:
var app = angular.module('app', ['ui.grid', 'ngSanitize']);
app.controller('MainCtrl', ['$scope', '$log', function ($scope, $log, $sce) {
$scope.myViewModel = {
someProp:'abc',
showMe : function(){
alert(this.someProp);
}
};
$scope.gridOptions = {
};
$scope.gridOptions.columnDefs = [
{ name: 'field01', field: 'field01' },
{ name: 'field02', field: 'field02'},
{ name: 'field03', field: 'field03', cellTemplate: '<input type="checkbox" ng-model="row.entity.field03" ng-click="$event.stopPropagation();getExternalScopes().showMe()">'},
{ name: 'field04', field: 'field04', cellTemplate: 'viewTemplate2'},
{ name: 'field05', field: 'field05', cellTemplate: 'viewTemplate2'}
];
$scope.gridOptions.data = [
{
"field01": "one",
"field02": "01",
"field03": false,
"field04": '',
"field05": '',
},
{
"field01": "two",
"field02": "02",
"field03": false,
"field04": '',
"field05": '',
},
{
"field01": "three",
"field02": "03",
"field03": false,
"field04": '<input type="checkbox" ng-model="row.entity.field03" ng-click="$event.stopPropagation();getExternalScopes().showMe()">',
"field05": '<div><img class="icon" alt=""/></div>',
}
];
$scope.toggle = function() {
alert("toggled");
}
}]);
Code from index.html:
<body>
<div ng-controller="MainCtrl">
<div ui-grid="gridOptions" external-scopes="myViewModel" class="grid"></div>
</div>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular-sanitize.min.js"></script>
<script src="app.js"></script>
<script type="text/ng-template" id="viewTemplate2">
<span ng-bind-html="row.entity[col.field]"></span>
</script>
</body>
I am achieving the correct effect in field03 if I write the html in the columnDef. Thanks to TomMorgan's plunker here: http://plnkr.co/edit/9eRg9Yjl2ooeSuWMJ8x2?p=preview.
I can fill the cellTemplate with html from the data in field05.
Why is it not working for my checkbox in field04?
I'm new to angularjs and its difficult to separate "ui-grid" solutions from "ng-grid" solutions. I appreciate the help.
I am not sure if I understand your code.
You shouldn't put html code in your data. So I changed it to:
$scope.gridOptions.data = [
{
"field01": "one",
"field02": "01",
"field03": false,
"field04": '',
"field05": '',
},
{
"field01": "two",
"field02": "02",
"field03": false,
"field04": '',
"field05": '',
},
{
"field01": "three",
"field02": "03",
"field03": false,
"field04": '',
"field05": '',
}
];
Next: In your cell template pass a reference to the value that changes:
{ name: 'field03', field: 'field03', cellTemplate: '<input type="checkbox"
ng-model="row.entity.field03" ng-click="$event.stopPropagation();
getExternalScopes().showMe(row.entity.field03)">'}
Note that function showMe() now has a parameter:
showMe(row.entity.field03)
In the external scope you should react to the parameter:
$scope.myViewModel = {
someProp:'abc',
showMe : function(value){
alert('toggled to: '+value);
}
};
(You don't really need someProp)
The $scope.toggle() function can be removed, or can be called from showMe().
Furthermore, I added some debugging help to your html to show you that the binding works pretty well:
<div ng-controller="MainCtrl">
<div ui-grid="gridOptions" external-scopes="myViewModel" class="grid"></div>
<hr>
{{gridOptions.data | json}}
</div>
Here is a Plunker. Is that what you want?
Update:
Here is another Plunker that has the checkbox in column 4.
Here is a Plunker with appScope, external-scopes don't work anymore.
I've made some changes to work with new appScope:
{ name: 'field03', field: 'field03', cellTemplate: '<input type="checkbox"
ng-model="row.entity.field03" ng-click="grid.appScope.showMe(row.entity.field03)">'}
In the scope you should react to the parameter but I've pulled from myViewModel and just created a function inside $scope:
$scope.showMe : function(value){
alert('toggled to: '+value);
};
You can test code from version 15 against my version 16. My new version runs ok but 15 no.
You need to use $sce to tell ng-bind-html that HTML content you are binding is safe.
I have forked your plunker and the solution for your question is http://plnkr.co/edit/JyTaF8niJlf9Wpb775kb?p=preview
app.filter('unsafe', function ($sce) {
return $sce.trustAsHtml;
});
You have to use this filter with ng-bind-html

Auto-complete doesn't work as expected

I tried to implement this in MVC 5 with jquery ui 1.10.2
#{
ViewBag.Title = "Home Page";
Layout = null;
}
<p>
Enter country name #Html.TextBox("Country")
<input type="submit" id="GetCustomers" value="Submit" />
</p>
<span id="rData"></span>
<script src="~/Scripts/jquery-1.10.2.min.js"></script>
<script src="~/Scripts/jquery-ui.js"></script>
#Styles.Render("~/Content/themes/base/css")
<script type="text/javascript">
$(document).ready(function () {
$("#Country").autocomplete({
source: function (request, response) {
$.ajax({
url: "/Home/AutoCompleteCountry",
type: "POST",
dataType: "json",
data: { term: request.term },
success: function(data) {
response($.map(data, function(item) {
return { label: item.Country, value: item.Country };
}));
}
});
}
});
})
</script>
the server side is
...
[HttpPost]
public JsonResult AutoCompleteCountry(string term)
{
// just something to return..
var list = new List<string>() { "option1", "option2", "option3"};
var result = (from r in list
select r);
return Json(result, JsonRequestBehavior.AllowGet);
}
}
I have two issues
1. it open up drop down autocomplete with 3 dots but without the actual strings.
2. It has this annoying message of "3 results were found" - I'd like to eliminate it..
DO you have any idea how to face those two issues or neater way to implement it in MVC5?
The 3 bullet points and "3 results were found" is because you are missing the jQuery UI css file. That file will format a drop down that will look a lot better. You can customize how the dropdown looks with additional css.
Also, you are seeing 3 empty results because your JS is referencing item.Country ...
return { label: item.Country, value: item.Country };
But your server code is just sending 3 strings.
new List<string>() { "option1", "option2", "option3"};
To fix, change your JS to just reference the item (the string) ...
return { label: item, value: item};
OR, change your server code to send more complex objects
new List<Object>() { new { Country = "option1" }, new { Country = "option2" }, new { Country = "option3" } };
use return data in place of return { label: item.Country, value: item.Country };

Resources