ASP.NET MVC Razor view hide table column - sitefinity

I am building a table in a view and only wanted this column to he visible if the mode is true? Is the if the only way to do this or is can I use something like hide , isvisible or #Html.HiddenFor?
#if(Model.IsLocationMode == true){
<th>#Html.DisplayNameFor(model => model.Location[0].Name))</th>
}
#if(Model.IsLocationMode == true){
<td>#obj.Name</td>
}

If you don't care about the data, then just use an empty placeholder to maintain your table structure. Or don't include it at all.
#if(Model.IsLocationMode == true) {
<td></td>
}
If you want to toggle the visibility with JavaScript when the user interacts with your page then use CSS.
#{
var hiddenClass = (Model.IsLocationMode ? "hidden" : "");
}
<td>
<div class="#hiddenClass">
#Html.DisplayNameFor(model => model.Location[0].Name)
</div>
</td>
And don't forget about the style rule
.hidden {
display: none;
}
Then you can use js to control the visibility in response to an event.
element.classList.toggle('hidden');

Related

VeeValidate not working with inline editing. I am using v-for and v-if for inline editing

I have user list inline editing table structure. Each row is represents a user. I am editing user and using vee validate for validation
validateState(ref) {
if (
this.veeFields[ref] &&
(this.veeFields[ref].dirty || this.veeFields[ref].validated)
) {
return !this.veeErrors.has(ref)
}
return null
},
saveUserUpdate: function(user) {
this.$validator.validateAll().then((result) => {
debugger
if (!result) {
return
} else {
//code to save user api
}
})
}
<tr v-for="(user, userIndex) in userList" :key="userIndex">
<td>
<span v-show="user.isEditing">
<b-form-input size="sm" v-model="user.fullName" :name="'tbnewFullName' + user.unique_id" :state="validateState('tbnewFullName' + userIndex)" :aria-describedby="'tbnewFullName-feedback' + userIndex"></b-form-input>
<b-form-invalid-feedback :id="'tbnewFullName-feedback' + userIndex">
Required.
</b-form-invalid-feedback>
</span>
<div v-show="!user.isEditing">
{{user.fullName}}
</div>
</td>
</tr>
I don't know what wrong I am doing here but validations are not fired in saveUserUpdate. veeFields list in validateState are not showing my user's name field. Also veeFields is showing list of fields from previous form.
You have to use v-model="userList[userIndex].fullName. See here for details. The summary is, due to how vee-validate works internally, they have trouble tracking the limited-in-scope user variable.

Aurelia if.bind inside repeat.for is not updating

I have a strange case in an Aurelia template of elements with if.bind inside a repeat.for not being shown/hidden when their underlying property is changed. With the following code, the edit fields should be shown and the edit button should be hidden as soon as the edit button is clicked. Subsequently, both the save and undo buttons should hide the edit fields and show the edit buttons again.
MyList.ts:
import { computedFrom } from "aurelia-binding";
export class MyList
{
items: any[] = [{
"firstName": "Joe",
"lastName" : "Blow",
"id": 1
},
{
"firstName": "Jane",
"lastName" : "Doe",
"id": 2
}
]
editingItem: any = null
isEditing: boolean;
edit(item){
this.editingItem = item;
this.isEditing = true;
}
editFirst(item){
this.editingItem = this.items[0];
this.isEditing = true;
}
undo(){
// undo logic here
this.editingItem = null;
this.isEditing = false;
}
save(){
// Save logic here
this.editingItem = null;
this.isEditing = false;
}
}
MyList.html:
<template>
<table>
<tbody>
<tr repeat.for="item of items">
<td if.bind="!isEditing">
<button click.delegate="edit(item)">Edit</button>
</td>
<td>${item.firstName}</td>
<td>${item.lastName}</td>
<td if.bind="isEditing && editingItem.id == item.id">
<button click.delegate="save()">Save</button>
<button click.delegate="undo()">Undo</button>
<input value.bind="editingItem.firstName" />
<input value.bind="editingItem.lastName" />
</td>
</tr>
</tbody>
</table>
</template>
Clicking the edit button does nothing. Interestingly, if I add
${isEditing}
Anywhere in the template outside the repeat.for, the code works as expected. It's as if the rendering engine doesn't know to re-render elements inside the repeat loop.
Is this a bug? Or am I doing something silly?
This is weird. I created a gist from your code and as you said it wasn't working. No errors in the console either.
But when I initialized isEditing it started working
isEditing: boolean = false;
Updated gist
From #Balázs in the comments: By not initializing the isEditing, that property virtually does not exist -- it can be used for autocompletion/IntelliSense, but it is not actually present on the object. You can verify that by replacing the console.log call in the edit method with console.log(this.editing);, you will see that it is undefined. By it being undefined, Aurelia cannot subscribe to it (because it is as though it wasn't even there - no getter/setter exists), and therefore has no way of knowing when, if ever, it comes to life. However, that even explicitly setting it to undefined is different from this, because that does actually create the property, whose value happens to be set to undefined.
Also note:
Since you are assigning editingItem directly with item here:
edit(item){
this.editingItem = item;
this.isEditing = true;
}
Whatever you change in editingItem will affect item as well. So even if you undo, the change will persist to item. So you should do a clone before assigning to editingItem.

How to input attribute for the polygon using ArcGIS API for Javascript?

I'm new at ArcGIS programming, I'm trying to input attribute for the polygon with draw script using ArcGIS API for JavaScript based on this: https://developers.arcgis.com/javascript/3/jssamples/toolbar_draw.html.
I try to input the attribute via windows pop up(the windows pop up was for base form input) using event draw complete,based on this: https://developers.arcgis.com/javascript/3/jsapi/draw-amd.html#event-draw-complete, but i fail because i don't know how to using it. My code was like this :
function initToolbar() {
tb = new Draw(map);
tb.on("draw-complete", addToMap);
// event delegation so a click handler is not
// needed for each individual button
on(dom.byId("tool"), "click", function(evt) {
if (evt.target.id == "tool") {
return;
}
var tool = evt.target.id.toLowerCase();
//map.hideZoomSlider();
tb.activate(tool);
});
}
function addToMap(evt) {
tb.deactivate();
//map.showZoomSlider();
switch (evt.geometry.type){
case "point":
case "multipoint":
symbol = new SimpleMarkerSymbol();
break;
case "polyline":
symbol = new SimpleLineSymbol();
break;
default:
symbol = new SimpleFillSymbol();
break;
}
var graphic = new Graphic(evt.geometry, symbol);
map.graphics.add(graphic);
}
Anyone can tell me, how to input attribute with another method ?
You could make a form with dojo framework, as ArcGis Javascript API is based on this framework.
Let's take this example from Dojo website : https://dojotoolkit.org/reference-guide/1.10/dijit/form/Form.html
This form asks for 2 values, a name and a date of birth.
Let's assume that corresponds to the attributes of your polygon.
Now, let's adapt it to your needs.
First, we take the html we need to build our form
<div data-dojo-type="dijit/form/Form" id="myForm" data-dojo-id="myForm" encType="multipart/form-data" action="" method="">
<table style="border: 1px solid #9f9f9f;" cellspacing="10">
<tr>
<td><label for="name">Name:</label></td><td><input type="text" id="name" name="name" required="true" data-dojo-type="dijit/form/ValidationTextBox"/></td>
</tr>
<tr>
<td><label for="dob">Date of birth:</label></td><td><input type="text" id="dob" name="dob" data-dojo-type="dijit/form/DateTextBox"/></td>
</tr>
</table>
<button data-dojo-type="dijit/form/Button" type="submit" name="submitButton" value="Submit">Submit</button>
<button data-dojo-type="dijit/form/Button" type="reset">Reset</button>
Now, the javascript code to handle the form. Make sure to merge it with your code, do not replace it.
require(["dojo/parser", "dojo/on", "dijit/registry", "dijit/form/Form", "dijit/form/Button", "dijit/form/ValidationTextBox", "dijit/form/DateTextBox", "dojo/domReady!"],
function(parser, on, registry) {
var attributes = {};
parser.parse();
var myForm = registry.byId("myForm");
on(myForm, "submit", function(){
if(this.validate()){
attributes = myForm.getValues();
delete attributes['submitButton'];
return true;
}else{
alert('Form contains invalid data. Please correct first');
return false;
}
});
on(myForm, "reset", function(){
return confirm('Press OK to reset widget values');
});
});
Finally, modify the last lines of your code, so it attaches the attributes from the form to the polygon, as described on the API doc :
var graphic = new Graphic(evt.geometry, symbol, attributes);
map.graphics.add(graphic);

asp.net Core View Component executed but markup not rendered

I have an ASP.NET Core 1.1 web application developed with VS.2017 and I decided to put some of the view functionality in a view component (have done others before).
This view component fetches a Dictionary collection of permissions associated to a user ID and displays them in a nice table. When I put it as part of the page (not VC) it works. But when I use it as a view component the component's HTML is never rendered.
I placed a breakpoint in the view component and it triggers, I see the View(granted) return statement return a populated list so up until there execution is as expected.
Then I placed a breakpoint in the ViewComponent's default.cshtml code section at the top the #{ some code here } and that breakpoint triggers as well, so the view component's Default.cshtml file is found. This Default.cshtml has some markup to render a table, therein within the table I have a #foreach() statement and when do a "Run to cursor" to that precise location -the loop that iterates- it triggers as well so it is iterating through the collection.
But after all that the main view looks as if the view component isn't there, none of the HTML found in the Default.cshtml is rendered even though it was found and executed. What am I missing here? so far my impression has been that VS.2017 (with all its updates) is not very stable.
Default.cshtml
#using ACME.AspNetCore.Permissions.Infrastructure.Authorization
#model Dictionary<Permission, string>
#{
ViewBag.UserName = "xxx";
Model.Add(Permission.Permission1, "test");
}
<h1>Component Output</h1>
<div class="well well-lg">
<table class="table table-hover">
<thead>
<tr>
<th>Permission</th>
<th>Description</th>
<th class="text-center">Status</th>
<th class="text-center">Revoke it!</th>
</tr>
</thead>
<tbody>
#foreach (var dictentry in Model)
{
<tr>
<td>#dictentry.Key.ToString()</td>
<td>#dictentry.Value</td>
<td class="text-center"><span class="glyphicon glyphicon-ok" style="color:green;"></span></td>
<td class="text-center"><a asp-action="RevokePermission" asp-route-id="#ViewBag.UserName" asp-route-pid="#dictentry.Key.ToString()"><span class="glyphicon glyphicon-thumbs-down" style="color:red;"></span></a></td>
</tr>
}
</tbody>
<tfoot><p class="alert alert-success"><span class="glyphicon glyphicon-eye-open"></span> Granted permissions</p></tfoot>
</table>
</div>
GrantedPermissionsViewComponent.cs
[ViewComponent(Name = "GrantedPermissions")]
public class GrantedPermissionsViewComponent : ViewComponent {
private readonly ApplicationDbContext _context;
public GrantedPermissionsViewComponent(ApplicationDbContext context) : base()
{
_context = context;
}
public async Task<IViewComponentResult> InvokeAsync(string emailOrUserId)
{
string id;
Guid UID;
if (Guid.TryParse(emailOrUserId, out UID))
{ // THE PARAMETER WAS A GUID, THUS A USER ID FROM IDENTITY DATABASE
id = emailOrUserId;
}
else
{ // THE PARAMETER IS ASSUMED TO BE AN EMAIL/USERNAME FROM WHICH WE CAN DERIVE THE USER ID
id = _context.Users.Where(u => u.Email == emailOrUserId.Trim()).Select(s => s.Id).FirstOrDefault();
}
Dictionary<Permission, string> granted = GetOwnerPermissions(id);
return View(granted);
}
private Dictionary<Permission, string> GetOwnerPermissions(string userId)
{
Dictionary<Permission, string> granted;
granted = _context.UserPermissions.Where(u => u.ApplicationUserId == userId)
.Select(t => new { t.Permission })
.AsEnumerable() // to clients memory
.Select(o => new KeyValuePair<Permission, string>(o.Permission, o.Permission.Description()))
.ToList()
.ToDictionary(x => x.Key, x => x.Value);
return granted;
}
}
So why on earth is it triggering on the component's code as well as on the component's view (default.cshtml) and yet it does not render the HTML code found therein?
Component invokation in the main view:
#{await Component.InvokeAsync<GrantedPermissionsViewComponent>(
new { emailOrUserId = ViewBag.UserName });
}
NOTE
The InvokeAsync is actually executing synchronously (per warning) because I could not find a way to have GetOwnerPermissions to await on anything... But that is not the problem.
The problem lies in how you are invoking the ViewComponent.
If you use #{ ... } it means you want to execute code and not render to output.
If you use parenthesis instead of brackets, the result gets rendered to output. #( ... )
In your case, you don't even need the parenthesis.
Try invoking it has following:
#await Component.InvokeAsync("GrantedPermissions", new { emailOrUserId = ViewBag.UserName })
More info here
try this, your mileage might vary. :)
#if (User.Identity.IsAuthenticated)
{
<div>User: #User.Identity.Name</div>
#(await Component.InvokeAsync("DefaultNavbar"));
#RenderBody()
}
else
{
<div> show public pages</div>
#RenderBody()
}

Assigning a Razor var using a Javascript function

On this page, a user fills out a web form, and it gets added to the list when created.
I want to filter the list so a logged in user will only see forms they made themselves.
I have some Razor code that runs a foreach loop through all available items, and I have Javascript that rips the currently logged in user's info.
is it possible to assign this data to a var in the razor code?
ex.
#{var user = getUser(); //want something like this }
#foreach (var item in Model) {
//add check if item.name == user.name here
<tr>
<td>
#Html.DisplayFor(modelItem => item.name)
</td>
etc etc
<script>
function getUser() {$.getJSON('GetLoggedUserInfo', function(data) {
return data;
});
</script>
I do not think it is a good idea to have this logic in a view. View should be as 'dumb' as possible.
You could make item filtering at data storage level or at least in controller:
return View(items.Where(x => x.name == user.name))
There is an easier way. You can get current user properties using:
HttpContext.Current.User