How to bind a Image column in MVC telerik Radgrid [duplicate] - telerik-mvc

Please let me know how to bind a image static image with all rows in Telerik Grid for ASP.NET MVC.
<%= Html.Telerik().Grid(Model.SearchResponse)
.Name("SearchGrid")
.Columns(columns =>
{
//Here i need to bind a static image column//
columns.Bound(grid => grid.Name);
columns.Bound(grid => grid.CaseNumber);
})
.Pageable(true)
%>

This is possible by adding another templated column to your collection:
Using ASPX
columns.Template(c => {
%><img alt="Static Image Alt Text" src="<%= Url.Content("~/myImage.jpg") %>"
/><%
}).Title("Static Image");
Using Razor
columns.Template(
#<text>
<img alt="Static Image Alt Text" src="#Url.Content("~/myImage.jpg") " />
</text>
).Title("Static Image");
UPDATE: If you wish to bind images from your model, please refer to the following example:
columns.Template(c => {
%>
<img
alt="<%= c.CustomerID %>"
src="<%= Url.Content("~/" + c.CustomerID + ".jpg") %>"
/>
<%
});
Or if you're using client templates, try the following:
.Columns(columns =>
{
columns.Bound(c => c.CustomerID)
.ClientTemplate("<img alt='<#= CustomerID #>' src='"
+ Url.Content("~/")
+ "<#= CustomerID #>.jpg' />")
.Title("Picture");
//omitted for brevity
}

This way we can bind image with every row.
we can also add Action with these images.
columns.Command(commands => commands.Custom("View").ButtonType(GridButtonType.BareImage)

Related

Blazor SFGrid Checkbox Selection is not working

I am trying to set up a check box in my grid for selection. Here is my sample grid looks like.
<div class="row section-top">
<div class="col">
<SfGrid #ref="GridInstance" DataSource="#_names" AllowSelection="true" AllowPaging="true">
<GridSelectionSettings CheckboxOnly="true" PersistSelection="true"></GridSelectionSettings>
<GridColumns>
<GridColumn Type="ColumnType.CheckBox" Width="50"></GridColumn>
<GridColumn Field="#nameof(Id)" HeaderText="Id" IsPrimaryKey="true"></GridColumn>
<GridColumn Field="#nameof(Name)" HeaderText="Name"></GridColumn>
</GridColumns>
</SfGrid>
</div>
</div>
It does show me checkbox and also select all works. But How Do i bind this to the grid so i can get the selected records/objects?
I tried this on click event but not working.
var selectedItems = this.GridInstance.GetSelectedRecordsAsync();
var selectedItemIds = new List<int>();
selectedItems.GetAwaiter().OnCompleted(() =>
{
selectedItemIds = selectedItems.Result.Select(s => s.Id).ToList();
});
Can anyone help how i can get selected grid rows from Syncfusion Blazor SFGrid?

Bind click handler to dynamically created DOM elements

In my Ionic 2 app I have a template with this code:
<div class="body" [innerHTML]="ticket.Body | safeHtml"></div>
The body is HTML that is returned from a remote API. That HTML can contain images. I want to bind a "click" event handler on those images so that I can open them in an InAppBrowser when a user taps on them.
What would be the best way to do that?
Angular 4.1.3, Ionic 3.3.0
Solution 1
Try binding an event on to the parent to capture clicked target elements.
// HTML file
<div class="body" [innerHTML]="ticket.Body | safeHtml" (click)="bodyDivClick($event)" >
</div>
// TS file
bodyDivClick(event) {
// Check if the clicked target is an Image element.
// You can also check by css class name for specific image elements.
if (event.target && event.target.tagName === 'IMG') {
let imageElem = event.target;
console.log('Image clicked');
}
}
Solution 2
You can also try using ngFor to loop your results (images) into view and bind an event on the image itself.
Assuming that ticket is a JSON parsed object retrieved from the remote API.
<div class="body">
<div *ngFor="let imageUrl of ticket.images; let i = index;" class="image-container" >
<img src="{{imageUrl}}" class="image-style" (click)="imageClick()" />
</div>
</div>
Most probably the first solution might work for you if you are not able to change the response of the Remote API from html to JSON/objects (if it's not implemented by you).

Is it possible to populate Episerver.Forms field with data

I'm using Episerver 10 together with Episerver.Forms addon. I created a form which contains several fields. I wonder if there's an option to prepopulate those fields with data.
Example:
A field for email address. If user is logged in I want this field to has email from user profile set as a value.
I created my own custom field for email and I tried to use SetDefaultValues method but apparently it's meant for something different.
EDIT:
My Custom form field:
public class PostalCodeFormField : TextboxElementBlock
{
public override void SetDefaultValues(ContentType contentType)
{
base.SetDefaultValues(contentType);
base.PredefinedValue = "Hello world";
}
}
Template for that field:
#model My.Valid.Namespace.PostalCodeFormField
<div class="Form__Element FormTextbox" data-epiforms-element-name="#Model.FormElement.ElementName">
<label for="#Model.FormElement.Guid">
My label
</label>
<p>#Model.PredefinedValue</p>
<input type="text" name="#Model.FormElement.ElementName" class="FormTextbox__Input" id="#Model.FormElement.Guid" value="#Model.PredefinedValue" />
<span data-epiforms-linked-name="#Model.FormElement.ElementName" class="Form__Element__ValidationError" style="display: none;">*</span>
</div>
Thing is #Model.PredefinedValue is empty like SetDefaultValues was never called
If you don't want to create a custom element (but i think that is the best solution) you can change the view of the element. It should be located under: \modules \ _protected \ EPiServer.Forms \ Views \ ElementBlocks
For your email example i would change the TextboxElementBlock.ascx into something like this:
<%# import namespace="System.Web.Mvc" %>
<%# import namespace="EPiServer.Web.Mvc.Html" %>
<%# import namespace="EPiServer.Forms.Core.Models" %>
<%# import namespace="EPiServer.Forms.Helpers" %>
<%# import namespace="EPiServer.Forms.Implementation.Elements" %>
<%# Import Namespace="EPiServer.Personalization" %>
<%# control language="C#" inherits="ViewUserControl<TextboxElementBlock>" %>
<%
var formElement = Model.FormElement;
var labelText = Model.Label;
var isEmailField = formElement.Validators.Any(x => x is EPiServer.Forms.Implementation.Validation.EmailValidator);
var defaultValue = Model.GetDefaultValue();
if (isEmailField)
{
defaultValue = EPiServerProfile.Current.Email;
}
%>
<div class="Form__Element FormTextbox <%: Model.GetValidationCssClasses() %>" data-epiforms-element-name="<%: formElement.ElementName %>">
<label for="<%: formElement.Guid %>" class="Form__Element__Caption"><%: labelText %></label>
<input name="<%: formElement.ElementName %>" id="<%: formElement.Guid %>" type="text" class="FormTextbox__Input"
placeholder="<%: Model.PlaceHolder %>" value="<%: defaultValue %>" <%: Html.Raw(Model.AttributesString) %> />
<span data-epiforms-linked-name="<%: formElement.ElementName %>" class="Form__Element__ValidationError" style="display: none;">*</span>
<%= Model.RenderDataList() %>
</div>
Edit:
Didn't see you edit the question. Remove the "base" from base.PredefinedValue in SetDefaultValues and it should work.
public class PostalCodeFormField : TextboxElementBlock
{
public override void SetDefaultValues(ContentType contentType)
{
base.SetDefaultValues(contentType);
PredefinedValue = "Hello world";
}
}
For setting a "dynamic value you can add a new property to the class (getting current user email here):
public virtual string UserEmail => EPiServerProfile.Current != null ? EPiServerProfile.Current.Email : string.Empty;
And update the input in the view:
<input type="text" name="#Model.FormElement.ElementName" class="FormTextbox__Input" id="#Model.FormElement.Guid" value="#Model.UserEmail" />
It is, but not out of the box. We typically solve this by creating custom elements.
David Knipe wrote an excellent blog on this, https://www.david-tec.com/2016/01/building-out-a-custom-form-element-with-the-new-episerver-forms/
Check the form model
public override void SetDefaultValues(ContentType contentType)
{
base.SetDefaultValues(contentType);
// override
base.PredefinedValue = "Hello world";
}
The new Episerver Forms has Autofill API to help you do exactly that job.

How to perform row double click event in kendo ui grid angular 2?

How to display orginal cell value in cell template <span> tag in angular 2 kendo ui grid.
Code
<ng-container ngFor="let col of grid.ColModel">
<kendo-grid-column [title]="col.Label" [field]="col.Name" [locked]="col.Locked" width="250px" *ngIf="hiddenColumns.indexOf(col.Name) === -1" >
<template kendoCellTemplate let-dataItem let-rowIndex="rowIndex" >
<span (dblclick)="open(rowIndex)">**{{dataItem}}** </span>
</template>
</kendo-grid-column>
</ng-container>
The example provided by Melanie might have worked in the past, but will not work with the Angular 2/4 Grid (if you click on the plunker, it won't load).
I have to do lots of debugging as I ran into the same issue.
The solution in a simple grid was as follows:
<kendo-grid #myGrid [selectable]="true" (dblclick)="dblClickEvent(myGrid, $event)">
<kendo-grid-column field="User" title="User" width="100">
</kendo-grid-column>
</kendo-grid>
in your .ts file, implement the event as follows:
dblClickEvent(grid, event) {
// debugger;
console.log('the selected row Index is '+ event.path[1].rowIndex);
//use the following line if you want to get the clicked cell content:
console.log('clicked cell content'+ event.path[0].textContent);
}
This would give your the selected row index, from which you can
Hope this helps.
The first argument in your double-click handler needs to be the double-click event (which you can access as $event in your template). You should pass that first and rowIndex second.
In addition, you're probably missing a lot of click events since you're using a span and your content is inside of a padded cell. I'd recommend that you make your entire cell a click target, for example by changing it to a div and getting rid of the padding on the containing td.
So your cell template might look like:
<kendo-grid-column field="MyField">
<template kendoGridCellTemplate let-dataItem let-rowIndex="rowIndex">
<div class="innerCell" (dblclick)="onRowDoubleClick($event, rowIndex)">
{{dataItem.MyField}}
</div>
</template>
</kendo-grid-column>
And your function:
onRowDoubleClick(evt, rowIndex) {
alert('You clicked row ' + rowIndex + '!');
}
And your styling:
td { padding: 0 !important; }
td > .innerCell { padding: 7px; cursor: pointer; }
Example: Plunker
Update:
If you have a sortable grid, you need to implement cellClick and dblClick like here:
https://stackblitz.com/edit/angular-ac3jzd?file=app/app.component.ts
This works for both: sorted and non sorted kendo grids
Orginal answer:
We like to define the dblclick on the grid and not on each column, So the answer from Adam works for us perfectly in chrome, but not in firefox.
Problem is that the path property is non-standard on the mouseevent and not provided in firefox (probably not in safari too)
Based on Adam's solution, we have solved it with:
<kendo-grid [selectable]="true" (dblclick)="dblClickEvent($event)">
<kendo-grid-column field="User" title="User" width="100"></kendo-grid-column>
</kendo-grid>
and:
dblClickEvent(event) {
let rowIndex;
if (event.path) { // works on chrome and all browsers supporting path property in mouseevent
rowIndex = event.path[1].rowIndex;
} else { // should work on all browsers
rowIndex = event.target.parentElement.rowIndex;
}
if (typeof rowIndex === 'number' && rowIndex < this.data.length) {
// do something
}
}
(this aussumes that the user has clicked inside a td-element)
Note: this does not work if the grid was sorted

Angular update ng-model in ng-repeat

Basically, I am trying to figure out a way to return a selected value (say, from a modal) to a specific model, when that model may be dynamically generated via ng-repeat.
So this is what my data looks like:
{
"title": "Example Title",
"enabled": true,
"thumbnailImage": "file1.png",
"content": [{
"order": 0,
"type": "wysiwyg",
"content": "<div>This is wysiwyg content!</div>"
},
{
"order": 1,
"type": "image",
"content": "file2.png"
}],
"id": 1
}
Now, the user can keep generating additional content by clicking a button that adds a new object with their selected type to the 'content' array. So an article may have one content image, or a hundred, or none (but will always have the 'thumbnailImage').
Using https://github.com/nervgh/angular-file-upload, I have added a modal which allows users to either upload a new image file, or select an existing image from the server. So my HTML looks a bit like this (for the ng-repeat content - similar for thumbnailImage):
<div class="Control">
<label>Content</label>
<div class="panel panel-default" ng-repeat="block in article.content">
<div class="panel-body">
<!-- ... other content types here ... -->
<div ng-if="block.type == 'image'">
<input type="text"
ng-model="block.content"
ng-if="block.type == 'image'"
class="form-control"
>
<a ng-click="selectImage()" class="btn btn-primary">Select image</a>
<button type="button" ng-if="!!activeImage" ng-click="block.content = activeImage" class="btn btn-secondary">Insert image</button>
</div>
</div>
</div>
</div>
selectImage() opens the modal, populates it with all the files already uploaded to the server, and has a drag-and-drop section allowing users to upload new images.
The modal looks like this:
<div ng-if="showFileManager" nv-file-drop uploader="uploader">
<div class="row">
<div ng-repeat="file in files" class="col-3">
<img ng-src="/{{ file.container }}/{{ file.name }}" ng-click="setActiveImage( file )">
</div>
</div>
<div ng-show="uploader.isHTML5">
<div nv-file-over uploader="uploader">
Drag and drop images to upload
</div>
</div>
</div>
What I am trying to do is on selecting an image, instantly populate the text input related to the 'selectImage()' button.
At the moment, clicking an image fires 'setActiveImage()', which is:
$scope.setActiveImage = function( file ) {
var filePath = 'http://localhost:3000/uploads/' + file.container + '/' + file.name;
$scope.activeImage = filePath;
};
And then the 'Insert image' button next to the 'Select image' button under each image updates the model. However, I'm hoping to be able to do that in the modal so all the user has to do is click the 'Close' modal button and the field is populated.
Does this make sense, and is it possible?
The way I get a specific item of ng-repeat is to pass it to a function in my view.
<html element ... useSelectedFile(file)></html element>
Then in your controller:
$scope.useSelectedFile = useSelectedFile;
function useSelectedFile(file){
//do stuff
//call function
//set scope item in view to file
}

Resources