Conditional HTML tag on Body tag - asp.net-core

On an ASP.NET Core 2.1 view I have the following:
<div #{if (1==1) { <text>style="background-image: url('image.png')"</text> }}></div>
Note: I am using 1==1 just for testing ...
This renders fine but I need to apply this to body tag:
<body #{if (1==1) { <text>style="background-image: url('image.png')"</text> }}>
In this case I get the error:
The tag helper 'body' must not have C# in the element's attribute declaration area.
How to solve this?

What you are writing doesn't seem to result in valid HTML.
Here are a few ideas (in order of complexity) to get you started.
Traditional conditional
<body>
#if (1 == 1)
{
<div style="background-image: url('image.png')"></div>
}
else
{
<div></div>
}
</body>
Ternary Operator
<div style="#((1 == 1) ? "background-image: url('image.png')" : "")"></div>
Move logic to separate block
#{
var divStyle = "";
if (1 == 1)
{
divStyle = "background-image: url('image.png')";
}
}
<div style="#divStyle"></div>
Logic done server side and stored in model
#model MyViewModel
<div style="#Model.DivStyle"></div>
Inject service into View (Dependency Injection)
#inject StyleService _styleService
<div style="#_styleService.GetStyleIfTrue(1 == 1)"></div>

Related

How to access the validator results in an TYPO3 Extbase action?

I have an Extbase module with a new/create-action. The model has the #validate annotation in it.
So far so good, everything's working.
But: I don't like how the form-errors are presented in the view. I'd like to add a CSS class like error in the view to the fields that are not correctly filled in.
But the only way to access the errors in the form seems to be through the <f:form.validationResults>-Viewhelper.
When I try to debug the results with <f:debug>{validationResults}</f:debug> I get a NULL value.
How do I access an error for a single field?
Actually, I'd prefer to access the errors in the controller, so I could pass an array to the view with the fields that contain an error.
I'm using Fluid and TYPO3 9.5
Such Fluid template should work out-of-the-box:
<f:form.validationResults>
<f:if condition="{validationResults.flattenedErrors}">
<ul>
<f:for each="{validationResults.flattenedErrors}" key="propertyPath" as="errors">
<li>
{propertyPath}: <ul>
<f:for each="{errors}" as="error">
<li>{error}</li>
</f:for>
</ul>
</li>
</f:for></ul>
</f:if>
</f:form.validationResults>
Another approach,
You can also write own ViewHelper to display error messages as you want in your own form HTML markup:
<?php
namespace VENDOR\Yourext\ViewHelpers;
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
/**
* #author Marcus Biesioroff biesior#gmail.com>
*
* ViewHelper for displaying custom-designed errors
*
* Usage:
* {namespace yvh=VENDOR\Yourext\ViewHelpers}
* or in ext_tables.php:
* $GLOBALS['TYPO3_CONF_VARS']['SYS']['fluid']['namespaces']['yvh'] = ['VENDOR\Yourext\ViewHelpers'];
*
* <yvh:myError key="yourObj.somefield" flattenedErrors="{validationResults.flattenedErrors}"/>
*/
class MyErrorViewHelper extends AbstractViewHelper
{
protected $escapeOutput = false;
public function initializeArguments()
{
parent::initializeArguments();
$this->registerArgument('key', 'sring', 'Name of the field for which errors should be displayed');
$this->registerArgument('flattenedErrors', 'mixed', 'Flatenned errors if any');
}
public function render()
{
$flattenedErrors = $this->arguments['flattenedErrors'];
if (is_null($flattenedErrors)) return null;
// DebuggerUtility::var_dump($flattenedErrors);
$key = $this->arguments['key'];
if (is_array($flattenedErrors) && array_key_exists($key, $flattenedErrors)) {
$errMsg = $flattenedErrors[$key][0]->getMessage();
return "<div class='my-very-own-error-class'>$errMsg</div>";
}
return null;
}
}
Remember, that you'll need to wrap your fields with <f anyway to get the flattenErrors array;
{namespace yvh=VENDOR\Yourext\ViewHelpers}
<f:form.validationResults>
<div>
<label for="name">Name (required)</label>
<f:form.textfield property="name"/>
<yvh:myError key="yourObj.name" flattenedErrors="{validationResults.flattenedErrors}"/>
</div>
<div>
<label for="slug">Slug (required)</label><br/>
<f:form.textfield property="slug"/>
<yvh:myError key="yourObj.slug" flattenedErrors="{validationResults.flattenedErrors}"/>
</div>
<div>
<label for="buildYear">Year of build (required)</label>
<f:form.textfield property="buildYear"/>
<yvh:myError key="yourObj.buildYear" flattenedErrors="{validationResults.flattenedErrors}"/>
</div>
</f:form.validationResults>

In Asp.Net Core, how can I get the multipart/form-data from the body?

In Asp.Net Core, it appears that they have done away with the Request.Content.ReadAsMultipartAsync functionality in favor of the IFormFile.
This makes uploading where you have an actual file a LOT easier, however, I have a use case where I need to upload a file to browser memory, process it, then send it as part of the multi-form data in the body. IFormFile cannot see this as there is no actual file to read. It only works if you have a filename property on the Content-Disposition and an actual file on the client to upload.
In my Asp.Net 4 app, I could read the mutlipart data in the body whether that was sent between boundaries or as an attached file.
How do I accomplish this in .Net Core?
What I figured out is that the multipart values are passed into the HttpRequest.Form as an array of key/value pairs. The "name" value on the body's multipart determines the name of the key.
I created a helper method that grabs both files and form values.
public static List<FileModel> GetFileModelsFromRequest(HttpRequest request)
{
var fileModels = new FileModels();
foreach (var formField in request.Form)
{
// Form data
var fileModelText = formField.Value;
... process and add to the FileModel list
}
if (request.Form.Files != null && request.Form.Files.Count > 0)
{
foreach (var file in request.Form.Files)
{
using (MemoryStream ms = new MemoryStream())
{
// File data
formFile.CopyTo(ms);
}
... process and add to the FileModel list
}
}
return fileModels;
}
I have done it this way. when I had to capture image from webcam and process (show that image in browser) it in browser memory and later on post that image using a form.
public IActionResult Index()
{
var files = HttpContext.Request.Form.Files;
if (files != null)
{
foreach (var file in files)
{
var fileName = file.Name;
}
}
return View();
}
I used a JS library Webcam.js to capture image from webcam and show that image on the same page. and once a user is satisfied with the image, s/he can upload the image to the server.
<!-- Configure settings and attach camera -->
<script language="JavaScript">
Webcam.set({
width: 320,
height: 240,
image_format: 'jpeg',
jpeg_quality: 90
});
Webcam.attach('#camera');
</script>
<!-- handle snapshot and displaying it locally -->
<script language="JavaScript">
function take_snapshot() {
// take snapshot and get image data
Webcam.snap(function (data_uri) {
// display results in page
document.getElementById('imageResults').innerHTML =
'<img src="' +
data_uri +
'"/>';
Webcam.upload(data_uri,
'/Default/Index',
function (code, text) {
console.log('Photo Captured');
});
});
}
</script>
<div class="panel panel-default">
<div class="panel-heading">Camera</div>
<div class="panel-body">
<div id="camera"></div>
<!-- A button for taking snaps -->
<form>
<input type="button" class="btn btn-success" value="Take Snapshot" onClick="take_snapshot()">
</form>
<div class="panel panel-default">
<div class="panel-heading">Captured Image</div>
<div class="panel-body">
<div id="imageResults">captured image will appear here...</div>
</div>
<br />
<br />
</div>
let me know if this is what you are looking for.

Knockout viewmodel: retrieving data from .Net Core controller

How do I update the Knockout viewmodel with data from my Razor model? My Razor page is generated from a simple GET Action in a .NET Core MVC project. The simple view is:
#model Birder2.ViewModels.SalesOrderViewModel
#using Newtonsoft.Json
#{ string data = JsonConvert.SerializeObject(Model); }
<script src="~/js/salesorderviewmodel.js"></script>
<script type='text/javascript' src="~/js/knockout-3.4.2.js"></script>
<script type='text/javascript'>
var salesOrderViewModel = new SalesOrderViewModel(#Html.Raw(data));
ko.applyBindings(salesOrderViewModel);
</script>
<p data-bind="text: MessageToClient"></p>
<div>
<div>
<label>Customer Name</label>
<span data-bind="text: CustomerName"></span>
</div>
<div>
<label>PO No.</label>
<span data-bind="text: PONumber"></span>
</div>
I have the following Knockout viewmodel, which is referenced above:
SalesOrderItemViewModel = function (data) {
var self = this;
ko.mapping.fromJS(data, {}, self);
The controller is here:
public async Task<IActionResult> Details(int? id)
SalesOrderViewModel salesOrderViewModel = new SalesOrderViewModel()
{
SalesOrderId = salesOrder.SalesOrderId,
CustomerName = salesOrder.CustomerName,
PONumber = salesOrder.PONumber
};
salesOrderViewModel.MessageToClient = "I originated from the viewmodel, rather than the model.";
return View(salesOrderViewModel);
I am very new to Knockout. Unfortunately I cannot find any effective documentation specific to .NET Core. The problem seems to be updating the Knockout viewmodel. The view is rendered with empty data fields.
Can anyone help identify the issue?
Everything looks correct. The only thing you should try is to place your script with ko.applyBindings(salesOrderViewModel) below your html with databinds
Alternatively you can use window.onload:
window.onload = function() {
var salesOrderViewModel = new SalesOrderViewModel(#Html.Raw(data));
ko.applyBindings(salesOrderViewModel);
};

Aurelia iterate over map where keys are strings

I'm having trouble getting Aurelia to iterate over a map where the keys are strings (UUIDs).
Here is an example of the data I'm getting from an API running somewhere else:
my_data = {
"5EI22GER7NE2XLDCPXPT5I2ABE": {
"my_property": "a value"
},
"XWBFODLN6FHGXN3TWF22RBDA7A": {
"my_property": "another value"
}
}
And I'm trying to use something like this:
<template>
<div class="my_class">
<ul class="list-group">
<li repeat.for="[key, value] of my_data" class="list-group-item">
<span>${key} - ${value.my_property}</span>
</li>
</ul>
</div>
</template>
But Aurelia is telling me that Value for 'my_data' is non-repeatable.
I've found various answer by googling, but they have not been clearly explained or incomplete. Either I'm googling wrong or a good SO question and answer is needed.
As another resource to the one supplied by ry8806, I also use a Value Converter:
export class KeysValueConverter {
toView(obj) {
if (obj !== null && typeof obj === 'object') {
return Reflect.ownKeys(obj).filter(x => x !== '__observers__');
} else {
return null;
}
}
}
It can easily be used to do what you're attempting, like this:
<template>
<div class="my_class">
<ul class="list-group">
<li repeat.for="key of my_data | keys" class="list-group-item">
<span>${key} - ${my_data[key]}</span>
</li>
</ul>
</div>
</template>
The easiest method would be to convert this into an array yourself (in the ViewModel code)
Or you could use a ValueConverter inside repeat.for as described in this article Iterating Objects
The code...
// A ValueConverter for iterating an Object's properties inside of a repeat.for in Aurelia
export class ObjectKeysValueConverter {
toView(obj) {
// Create a temporary array to populate with object keys
let temp = [];
// A basic for..in loop to get object properties
// https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Statements/for...in
for (let prop in obj) {
if (obj.hasOwnProperty(prop)) {
temp.push(obj[prop]);
}
}
return temp;
}
}
/**
* Usage
* Shows how to use the custom ValueConverter to iterate an objects properties
* aka its keys.
*
* <require from="ObjectKeys"></require>
* <li repeat.for="prop of myVmObject | objectKeys">${prop}</li>
*/
OR, you could use the Aurelia Repeat Strategies provided by an Aurelia Core Team member
You'd have to import the plugin into your app.
Then you'd use it using the pipe syntax in your repeat.for....like so....
<div repeat.for="[key, value] of data | iterable">
${key} ${value.my_property}
</div>

MVC 4 how to add a <div> element conditionally

Want to add a HTML (div) element conditionally. But code exerpt from my Create.cshtml does not work as the parser gets mixed up missing the end-div (the first closing "}" is no code anymore)
#if (setDiv)
{
<div class="#item.DivClass" id="#item.DivId">
}
// More code more HTML
if (setDiv)
{
</div>
}
Anyone an idea how to tackle this problem? Thanks in advance!
Gerard
You have to encapsulate your opening and closing divs in #Html.Raw(). Otherwise razor will not allow this syntax as it does not know that the div that you opened in one if statement is actually closed in another.
#if (setDiv)
{
#Html.Raw("<div class='#item.DivClass' id='#item.DivId'>")
}
// More code more HTML
#if (setDiv)
{
#Html.Raw("</div>")
}
Try this:
#if (setDiv)
{
<div class="#item.DivClass" id="#item.DivId">
}
// More code more HTML
#if (setDiv)
{
#:</div>
}