I want to use Url.Action with Knockout - asp.net-mvc

I am new to knockout and I am having trouble getting the syntax right when using it with MVC markup.
For example this code here;
<a href="text.Answer" target="_blank">
<span style="display:inline-block">
<img src="#Url.Action("GetPhotoThumbnail", new { path = text.Answer, width = 120, height = 80 })" alt="Property Image" style="margin-top: 5px;" />
</span>
</a>
EDIT
So "Answer" is in the ViewModel and in knockout you would type data-bind="text:Answer" but here I have put in 2 places text.Answer. How do I replace text.Answer in the above code with the correct Knockout markup?
I know the above code will not work but this is a simplified way of showing the problem. I want to data-bind to text.Answer. What is the correct syntax for doing that?

If I understood you correctly that your text.Answer is something bind in client side.
You can't mix #Url.Action with client side variables
Try creating your URL like this
"#Url.Action("GetPhotoThumbnail")?path="+variable1+"&width="+variable2+"&height=" +variable3

You could pass the values you need into the ViewModel.
<div id="test">
<a href="#" data-bind="attr: { href: href }" target="_blank">
<span style="display:inline-block">
<img src="" data-bind="attr: { src: imageUrl }" alt="Property Image" style="margin-top: 5px;" />
</span>
</a>
</div>
<script type="text/javascript">
function MyViewModel(defaultValues) {
this.href = defaultValues.href;
this.imageUrl = defaltValues.imageUrl
}
var viewModel = new MyViewModel({
imageUrl: '#Url.Action("GetPhotoThumbnail", new { path = text.Answer, width = 120, height = 80 })',
href: '#Url.Action("Test")'
});
ko.applyBindings(viewModel, document.getElementById('test'));
</script>

I'm guessing you've got a view model binded to this part of the DOM, so you should be able to use the data-bind attribute and the attr binding to achieve the following:
<a href="" data-bind="attr : { href: text.Answer } " target="_blank">
<span style="display:inline-block">
<img src="#Url.Action("GetPhotoThumbnail", new { path = text.Answer, width = 120, height = 80 })" alt="Property Image" style="margin-top: 5px;" />
</span>
</a>
See http://knockoutjs.com/documentation/attr-binding.html for more details on this binding.
Also you'll need to make the view model generate you the img[src] attribute value so try something like:
<img data-bind="attr:{ src: text.answerImgSrc() } " alt="Property Image" style="margin-top: 5px;" />

Related

Have a custom img blot with addEventListener. Event triggered when using insertEmbed, but it does not work when img loaded from existing html

I'm using react-native-cn-quill but this is really a Quilljs question. Thanks for your help.
In the code below, clickHandler is called on click when I do a "insertEmbed(index, 'pbThumbnail', obj)", but when I load the webView with initialHtml containing:
<span class="pb-Thumbnail">
<img class="pbVidThumb" ....>
</span>
the eventListener does not appear to be added to the blot/tag. Should the eventListener be automatically applied OR do I have to manually re-add to all the relevant tags?
Thanks for your help!
This is the custom blot, whose eventListener works when using insertEmbed:
const Block = Quill.import('blots/block');
class ThumbnailBlot extends Block {
constructor(domNode) {
super(domNode);
// Bind our click handler to the class.
this.clickHandler = this.clickHandler.bind(this);
domNode.addEventListener('click', this.clickHandler);
}
clickHandler(event) {
alert("ClickableSpan was clicked. Blot: ", this);
}
static create(value) {
let node = super.create();
node.setAttribute('contenteditable', false);
let image = document.createElement('img');
image.setAttribute('class', 'pbVidThumb');
image.setAttribute('contenteditable', false);
image.setAttribute('src', value.imgBase64);
image.setAttribute('height', value.height);
image.setAttribute('width', value.width);
image.setAttribute('id', value.imgName);
node.appendChild(image);
return node;
}
static value(node) {
return { src: node.getAttribute('src'), title: node.getAttribute('title'), height: node.getAttribute('height'), width: node.getAttribute('width'), id: node.getAttribute('id')}
}
static deleteAt(node) { return false; }
static formats(node) {
return node.getAttribute('title');
}
}
ThumbnailBlot.blotName = 'pbThumbnail';
ThumbnailBlot.tagName = 'span';
ThumbnailBlot.className = 'pb-thumbnail';
Quill.register(ThumbnailBlot);
Loading the below HTML into a webview with quill does not apply the click eventListener:
<span class="pb-thumbnail" contenteditable="false" title="IMG_0002.JPG">
<img contenteditable="false"
src="https://....uploads%2F2h06dnjjxoa8l21i5m51c-Bump-bump-imageimage.jpg"
height="auto"
width="100%"
class="pbVidThumb"
id="IMG_0002.JPG" >
</span>
Doing more debugging, I also noticed that the raw HTML that is loaded into the Quill editor gets reduced:
<div id="editor-container">
<h1>Pipi</h1>
<p><br></p>
<p><br></p>
<p><strong>I am grateful for...</strong></p>
<p><br></p>
<p><br></p>
<p><br></p>
<span class="pb-thumbnail"
contenteditable="false"
title="IMG_0002.JPG">
<img contenteditable="false"
src="https://uploads%2F656jhlsiw6xrc07t8i70g-Bump-bump-imageimage.jpg"
height="auto"
width="100%"
class="pbVidThumb"
imglocalpath="405B8B56-5718-421E-81EE-BBB7895D64BD.jpg"
vidlocalpath="EMPTY-1f051ea8-8c5d-4a9d-b8b1-597c0d2edfa4"
id="IMG_0002.JPG"
data-name="IMG_0002.JPG"
data-long-press-delay="250">
</span>
<p><br></p>
</div>
When I use codePen playground, and with the above html code in the editor, and I do: console.log(document.getElementById("editor-container")); what I see is:
<div id="editor-container" class="ql-container ql-snow">
<div class="ql-editor" data-gramm="false" contenteditable="true" data-placeholder="Compose an epic..."›
<h1>Pipi</h1>
<p><br></p>
<p><br></p>
<p> <strong>I am grateful for...</strong></p>
<p><br></p>
<p><br></p>
<p><br></p>
<p><br></p>
<p><img src="https://uploads%2F656jhlsiv6xrc07t8170g-Bump-bump-imageimage.jpg"
height="auto"
width="1009"></p>
</div>
<div class="ql-clipboard" contenteditable="true" tabindex="-1"></div><div class="ql-tooltip ql-hidden"><a class="ql-preview" target="_blank" href="about:blank"></a><input type="text" data-formula="e=mc^2" data-link="https://quilljs.com" data-video="Embed URL"><a class="ql-action"></a><a class="ql-remove"></a></div></div>
All the class tags I used are gone along with many attributes. Why is that?

How anchor tag is firing an HTML Action in MVC?

I have the following code:-
<div class="control-group">
<label class="control-label"><b>Contact</b> <span style="color: #f00; font-size: larger;">*</span></label>
<div class="controls input-append">
<input disabled="disabled" style="width: 210px" type="text" id="id-lookup-addjllcontact-contactid" defaultoid=""
defaultvalue="" oid="" value=""
field="SystemUserId" otype="systemuser">
<a class="btn" id="btn-lookup-addjllcontact-contactid"><i class="icon-search"></i></a>
</div>
</div>
<div>
#Html.Action("_LookupSearchPartial", "Lookup",
new
{
ParentFormId = "form-addjllcontact",
LookupInputId = "id-lookup-addjllcontact-contactid",
LookupButtonId = "btn-lookup-addjllcontact-contactid",
UniqueId = Guid.NewGuid(),
EntityType = "systemuser",
AttributeName = "systemuserid",
AttributeDisplayName = "FullName"
})
</div>
When I click anchor with id as "btn-lookup-addjllcontact-contactid", it fires the HTML Action. Can any one tell me how ? Also I want to know how can display the result of the HTML Action in a modal.
There was Javascript in the page somewhere hidden which was doing it. This was a generic javascript file that was handling all the lookups in the application.
this.lookupInput = $('#' + this._config.LookupInputId);
this.lookupButton.live("click", this, JLL.Lookup.Search.showLookup);

Foreach not updating HTML list elements

Using knockout 2.2.0
I'm trying to use the same dialog for add and edit. I have the code mostly working, but when I replace the observable with the new edited one, it doesn't cause an update in the foreach (or at least it continues to display the old values) It does update the actual model, as I can see in dev tools. I even tried to force an update with .valueHasMutated(), but with no luck.
self.editReference = function () {
self.isEdit(true);
self.open();
self.dialogReferences(this);
};
self.saveEditReference = function () {
self.references.replace(this, self.dialogReferences);
self.references.valueHasMutated();
self.dialogReferences(newReferences());
self.close();
};
And here is the some of the partial view with the references section of HTML code:
<ul class="sortable references-summary" data-bind="foreach: references">
<li class="ui-state-default"><b>Name: </b><!-- ko text:name --><!-- /ko--><br /><b>Company: </b><!-- ko text:company --><!-- /ko--><span class="ui-icon ui-icon-closethick"></span><span class="ui-icon ui-icon-wrench"></span></li>
</ul>
Thanks to CrimsonChris for pointing out my bug. The updated code below works as expected.
The approach is to have a reference you are editing, in addition to the references in your array. When you start to edit, you copy the values from the array to your edit reference. When you save the edit, you copy them back. There is no need for valueHasMutated for this to work.
function reference(name, company) {
return {
name: ko.observable(name),
company: ko.observable(company)
};
}
// Copy r1 into r2
reference.copy = function(r1, r2) {
r2.name(r1.name());
r2.company(r1.company());
}
var self = {
editingReference: undefined,
dialogReferences: reference('', ''),
references: ko.observableArray([
reference('One', 'First Company'),
reference('Two', '2nd Company')
]),
dialogIsOpen: ko.observable(false),
open: function() {
self.dialogIsOpen(true);
},
close: function() {
self.dialogIsOpen(false);
}
};
self.editReference = function(item) {
self.editingReference = item;
self.open();
reference.copy(item, self.dialogReferences);
};
self.removeReference = function(item) {
self.references.remove(item);
self.close();
};
self.saveEditReference = function(item) {
reference.copy(item, self.editingReference);
self.close();
};
ko.applyBindings(self);
<link href="//code.jquery.com/ui/1.11.3/themes/smoothness/jquery-ui.css" rel="stylesheet" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/knockout/2.2.0/knockout-min.js"></script>
<ul class="sortable references-summary" data-bind="foreach: references">
<li class="ui-state-default"> <b>Name: </b>
<!-- ko text:name() -->
<!-- /ko-->
<br /> <b>Company: </b>
<!-- ko text:company() -->
<!-- /ko--> <span class="ui-icon ui-icon-closethick"></span>
<span class="ui-icon ui-icon-wrench"></span>
</li>
</ul>
<div data-bind="if: dialogIsOpen">
<div data-bind="with:dialogReferences">
<label>Name</label>
<input data-bind="value:name" />
<br/>
<label>Company</label>
<input data-bind="value:company" />
<input type="button" value="Save" data-bind="click: $parent.saveEditReference" />
</div>
</div>

File Upload using recent Bootstrap file upload and mvc asp.net

I looked over some other answers and the solutions there were not working. And I couldn't seem to figure out why. This is using Bootstrap 3.0. All I am trying to do is use that to upload a new avatar image. The problem is it always comes up null and I cannot seem to figure out why.
Here is my HTML:
#using (Html.BeginForm("EditAvatar", "Profile", new { userID = #Model.ProPit_User.userID }, FormMethod.Post, new { }))
{
<div class="form-group">
<div class="fileinput fileinput-new" data-provides="fileinput">
<div class="fileinput-new thumbnail" style="width: 200px; height: 150px;">
<img src="http://www.placehold.it/200x150/EFEFEF/AAAAAA&text=no+image" alt="" />
</div>
<div class="fileinput-preview fileinput-exists thumbnail" style="max-width: 200px; max-height: 150px;">
</div>
<div>
<span class="btn default btn-file">
<span class="fileinput-new">Select image
</span>
<span class="fileinput-exists">Change
</span>
<input id="avatar_image" type="file" name="..." runat="server">
</span>
<a href="#" class="btn default fileinput-exists" data-dismiss="fileinput">Remove
</a>
</div>
</div>
<div class="clearfix margin-top-10">
<span class="label label-danger">NOTE!
</span>
<span>Attached image thumbnail is supported in Latest Firefox, Chrome, Opera, Safari and Internet Explorer 10 only
</span>
</div>
</div>
<div class="margin-top-10">
<button type="submit" class="btn green">
Save Changes
</button>
<button type="reset" class="btn default">Cancel</button>
</div>
}
I have given the file input the ID of avatar_image
Here is the controller:
[HttpPost]
public ActionResult EditAvatar(HtmlInputFile avatar_image)
{
if (avatar_image.PostedFile != null)
{
//do whatever you want with the file
}
return View();
}
When looking at the break point the avatar_image.PostedFile is always null. Anyone have any idea what I am missing?
You might check the request in Fiddler. More importantly though, you need to add the enctype="multipart/form-data" attribute to the form.

Image as a submit button

I'm changing the buttons to images which are used for OAuth (see oauth2 tutorial).
I'm also grayscaling those images, and for this I use this code.
This is my _ExternalLoginsPartial.cshtml:
#{
var loginProviders = Context.GetOwinContext().Authentication.GetExternalAuthenticationTypes();
string action = Model.Action;
string returnUrl = Model.ReturnUrl;
using (Html.BeginForm(action, "Account", new { ReturnUrl = returnUrl }))
{
#Html.AntiForgeryToken()
foreach (AuthenticationDescription p in loginProviders)
{
<ul class="imglist" id="socialLogin">
#if (p.AuthenticationType == "Google")
{
<li><img src="/Content/google.png" /></li>
<li><img src="/Content/google.png" /></li>
<li><img src="/Content/google.png" /></li>
}
#if (p.AuthenticationType == "Microsoft")
{
<li><img src="/Content/outlook.jpg" /></li>
}
#if (p.AuthenticationType == "Facebook")
{
<li><img src="/Content/facebook.png" /></li>
}
</ul>
}
}
}
I can't remove the <a href="#"> because that will break the grayscaling.
And I can't place a button tag inside it, because that is bad HTML (compiler complains about it if done so).
So how can I turn these images to act like a submit button?
EDIT:
http://i61.tinypic.com/2ns7t00.png
You can replace the anchor element with a button element but you will have to change the code a little:
<button type="submit"><img src="..."></button>
Then change the selectors in the code:
$(window).load(function() {
$('button img').each(function() {
...
});
$(document).ready(function() {
$("button").hover(
...
);
});
If you want to get rid of the button styles, just use css:
button {
padding: 0;
border: none;
}
You could submit the form with Javascript by clicking on a link:
using (Html.BeginForm(action, "Account", new { ReturnUrl = returnUrl, id = "myId" }))
{
<a href="#" onclick="document.getElementById('myId').submit();">
<img src="/Content/facebook.png" />
</a>
}
This is just sample code for how you could add an id to the form and add a click event on the link.
You can do something like <input type="image" src="submit.gif"> which will submit your page within the form tag. An alternative would be to use jQuery and create a click event for the image.
As you specified in a response to another question, you wanted to return a value as well you could do this instead: (based off of Kevin's Answer)
using (Html.BeginForm(action, "Account", new { ReturnUrl = returnUrl, id = "myId" }))
{
<a href="#" onclick="document.getElementById('#p.AuthenticationType').click();">
<img src="/Content/facebook.png" />
</a>
<input name ="provider" type="submit" style="display:none;" id="#p.AuthenticationType" value="#p.AuthenticationType" />
}

Resources