AngularJS: compiled html alternates content - asp.net-mvc

Here is a simple element directive that displays a name in bold:
WidgetsModule.directive('testwidget', function () {
return {
restrict: 'E',
scope: {
name: '#'
},
template: '<p>My name is <b>{{name}}</b></p>',
controller: function ($scope) {
this.title = $scope.title;
}
};
})
This is a partial page of html that I load from the server:
<h1>My Partial Page</h1>
<testwidget name="Fred"></testwidget>
I have another directive called dymanicRefreshPanel, which has a div and a button. When the button is pressed, the partial page is requested by an ajax post, and inserted into an element like this:
link: function (scope, element, attr) {
scope.compileData = function (data) {
var el = $compile(data)(scope);
$(element).find("div.widget-body").html(el);
}
}
When I first load the dynamic content, the browser shows this:
My name is Fred
The second time I request dynamic content, the browser shows this:
My name is {{name}}
The third time, back to the original:
My name is Fred
And then back and forth between the two. The html that arrives by the ajax post is always the same.
What's going on?

Related

JQuery-ui Tabs - reload page with completely new content not working

I'm loading in a report and displaying it with jquery-ui in tab format. The report is returned by an ajax call in json, and a function is formatting it into HTML. Example code below:
<div id="reportdiv">
</div>
<script>
function displayreport(objectid)
{
$( "#reportdiv" ).hide();
$( "#reportdiv" ).html("");
$.ajax({
type: "GET",
headers: { 'authtoken': getToken() },
url:'/reportservice/v1/report/'+objectid.id,
success: function(data){
if(data == null)
{
alert("That report does not exist.");
}
else
{
var retHTML = dataToTabHTML(data.config);
$("#reportdiv").html(retHTML).fadeIn(500);
$(function() {
tabs = $( "#reportdiv" ).tabs();
tabs.find( ".ui-tabs-nav" ).sortable({
axis: "x",
stop: function() {
tabs.tabs( "refresh" );
}
});
});
}
}
});
}
</script>
This works fine the first time displayreport is called. However, if the user enters another value and runs displayreport again, the "tabs" format is completely lost (the tabs are displayed as links above my sections, and clicking on a link takes you to that section further down the page).
I figured completely re-setting the reportdiv html at the beginning of the function would bring me back to original state and allow it to work normally every time. Any suggestions?
After more testing, found that destroy was the way to go. If I've set up tabs already, run the destroy, otherwise, skip the destroy (http://jsfiddle.net/scmxyras/1/) :
if(tabs!=undefined)$( "#reportdiv" ).tabs("destroy");

HTML reponse after Ajax call is stripped of some tags

I am making an ajax call to a action in a controller which returns a partial view. The partial view is a row that will be appended or it will replace an existing row from a grid of items (depending if I am adding or editing a row item).
In the Network tab from Google Chrome I am getting the correct string of HTML like:
<tr class="" data-id="1c4daceb-2afb-413b-8adc-d20b4d8969e5">
<td><img style="width:100px; height:100px;" src="http://localhost/Project/6b39488b-db2d-495e-957c-ede0eb462292.png" data-id="1c4daceb-2afb-413b-8adc-d20b4d8969e5"/></td>
<td>bvcbvX</td>
<td>6b39488b-db2d-495e-957c-ede0eb462292.png</td>
</tr>
but in my Ajax success function:
function onDataEdited(data, status, xmlhttp) {
alert(data);
}
I get the row stripped of and tags, like this:
<img style="width:100px; height:100px;" src="http://localhost/Project/6b39488b-db2d-495e-957c-ede0eb462292.png" data-id="1c4daceb-2afb-413b-8adc-d20b4d8969e5"/>
bvcbvX
6b39488b-db2d-495e-957c-ede0eb462292.png
So something from jquery strips my tags leaving only the content.
The call to the action is done through Ajax like this:
function MakeAjaxCall() {
$('#myForm').ajaxForm({
iframe: true, ---> here is needed since I am adding a file upload from my form
beforeSubmit: function () {
if (!$('#myForm').valid())
//process validation
return $('#myForm').valid();
},
success: function (data, status, xmlhttp) {
if (xmlhttp.getResponseHeader('ErrorHeader') == null ||
xmlhttp.getResponseHeader('ErrorHeader') == "") {
//process success
}
else {
//process error
}
},
error: function (xhr, textStatus, errorThrown) {
alert(xhr);
}
});
}
Can anyone tell me how to get my response data without being stripped of and tags?
I am using this jquery plugin (malsup.com/jquery/form) for making the form "ajaxified" in order to submit a form that contains files through Ajax.
The 'ajaxForm' method from this plugin has as dataType only 'xml', 'json', 'script' and null - (which I am using) and the response is stil stripped of tags for 'xml'. If I set 'json' or 'script' it throws a client side errors specifying that it cannot parse the response (is trying to parse it as a script when it is html).
Could be an issue with the dataType: http://malsup.com/jquery/form/#options-object ?

jQuery Autocomplete wrong item in text box on select

When a user begins typing in the DRMCompanyName input text box, and autocomplete feature fires that displays both the company name and the company id. When the use clicks on a selection, the company name and id are to be placed into the DRMCompanyName text box and the id in the DRMCompanyId text box just below.
When the json results are returned from the controller, the code in the autocomplete ajax success function populates the drop down list by setting the label to be equal to the value (company name) plus the key (company id) being returned. Likewise the value is set to just the key (company id).
When the user selects a particular item, the label is supposed to go in the DRMCompanyName text box and the value in the DRMCompanyId. However, what winds up happening is the value gets placed in both.
I've scoured my code over and over and cannot find out why the label does not get placed in the DRMCompanyName field.
jQuery
$(function () {
$('#DRMCompanyName').autocomplete({
source: function (request, response) {
$.ajax({
url: '#Url.Action("compSearchByName", "AgentTransmission")',
type: 'GET',
dataType: 'json',
data: request,
success: function (data) {
response($.map(data, function (value, key) {
return {
label: value + " " + key,
value: key
};
}));
},
});
},
minLength: 2,
select: function (event, ui) {
console.log(ui);
$('#DRMCompanyName').val(ui.item.label);
$('#DRMCompanyName').text(ui.item.label);
if ($('#DRMCompanyId').text() == '') {
$('#DRMCompanyId').val(ui.item.value);
$('#DRMCompanyId').text(ui.item.value);
}
}
});
});
Here is a sample screen shot of the ui item from the select function above (the company name is blacked out for privacy). When I click on this particular item in the autocomplete drop down, 200014 gets placed in both the DRMCompanyName and DRMCompanyId fields.
Razor Markup
<div class="M-editor-field">
#Html.TextBoxFor(model => model.DRMCompanyName)
#Html.ValidationMessageFor(model => model.DRMCompanyName)
</div>
<div class="M-editor-label">
#Html.LabelFor(model => model.DRMCompanyId)
</div>
<div class="M-editor-field">
#Html.TextBoxFor(model => model.DRMCompanyId, new { maxlength = 10, title = "Start typing company name to activate DRM Company Name lookup. When DRM Company is found, select to fill in DRM Company ID and DRM Company Name fields." })
#Html.ValidationMessageFor(model => model.DRMCompanyId)
</div>
EDIT
After following the suggestion in the answer below, I modified the select function like so:
select: function (event, ui) {
console.log(tempResults[ui.item.value]);
$('#DRMCompanyName').val(tempResults[ui.item.value]);
$('#DRMCompanyName').text(tempResults[ui.item.value]);
if ($('#DRMCompanyId').text() == '') {
$('#DRMCompanyId').val(ui.item.value);
$('#DRMCompanyId').text(ui.item.value);
}
}
Based on the console.log readout, this accesses the correct value when the user clicks on the autocomplete item. However, it still places the value in both text boxes. What I can't understand, when I select Inspect Element, is that the correct value for DRMCompanyName actually is placed in the HTML, however it does not appear on the screen, only the id or value (as opposed to label).
You are setting label: value + " " + key which will of course add the id in the label.
When you set $('#DRMCompanyName').val(ui.item.label);, it's going to set what you concatenated in the $.map to the value.
One way to do this is to store a temporary result set from the data in the source ajax call to access later. With this temp set, you can now pull any object or key/value from it for use later.
When getting results, store a temporary list of the results.
var tempResults = [];
...
source: function (request, response) {
$.ajax({
url: '#Url.Action("compSearchByName", "AgentTransmission")',
type: 'GET',
dataType: 'json',
data: request,
success: function (data) {
tempResults = data;
response($.map(data, function (value, key) {
return {
label: value + " " + key,
value: key
};
}));
},
});
}
Then, on the select, you can now access the stored data and set values:
select: function (event, ui) {
event.preventDefault();
var name = tempResults[ui.item.value].value;
var id = tempResults[ui.item.value].key;
$('#DRMCompanyName').val(name);
$('#DRMCompanyName').text(name);
if ($('#DRMCompanyId').text() == '') {
$('#DRMCompanyId').val(id);
$('#DRMCompanyId').text(id);
}
}
EDIT
Forgetting one minor thing! Add this to the beginning of the select: function!
event.preventDefault();
By default, when selecting, the autocomplete will use the ui.item.value to populate the element that it's wired up with. Using event.preventDefault() will prevent the already wired up event handler to be called used within the autocomplete.
event.preventDefault() documentation.

jQuery Ajax Form Submit Fails

I am developing an MVC4 mobile app that uses several forms which are loaded into a section on the layout via ajax. I've got jQuery mobile set with Ajax turned off so I can manage the Ajax myself. Most of the forms work fine, the load and submit via ajax as they should. However, so far there is one form that refuses to fire the form submit and submit the form via ajax like the rest. First, the form is loaded when a user clicks to add a contact and this works fine:
// Handle the add contact button click
$('#btnAddNewContact').on('click', function (e) {
e.preventDefault();
// Make sure a location was selected first.
var locationID = $('#cboLocation').val();
if (locationID.length === 0) {
//$('#alertTitle').text('REQUIRED');
$('#alertMsg').html("<p>A Contact must be associated with a Location.</p><p>Please select or add a Location first.</p>");
$('#alertDialogDisplay').click();
} else {
SaveOpportunityFormState();
$.cookie('cmdLocationId', locationID, { path: '/' });
$.mobile.loading('show');
$.ajax({
url: '/Contact/Add',
type: 'GET',
cache: false,
success: function (response, status, XMLHttpRequest) {
$('section.ui-content-Override').html(response);
// Refresh the page to apply jQuery Mobile styles.
$('section.ui-content-Override').trigger('create');
// Force client side validation.
$.validator.unobtrusive.parse($('section.ui-content-Override'));
},
complete: function () {
$.cookie('cmdPreviousPage', '/Opportunity/Add', { path: '/' });
AddContactLoad();
ShowSearchHeader(false);
$.mobile.loading('hide');
},
error: function (xhr, status, error) {
// TODO - See if we need to handle errors here.
}
});
}
return false;
});
Notice that after successfully loading the form the AddContactLoad() function is fired. This works fine and here is that code:
function AddContactLoad() {
$('#contactVM_Phone').mask('(999) 999-9999? x99999');
$('#frmAddContact').on('submit', function (e) {
e.preventDefault();
if ($(this).valid()) {
$.mobile.loading('show');
$.ajax({
url: '/Contact/Add',
type: 'POST',
cache: false,
data: $(this).serialize(),
success: function (response, status, XMLHttpRequest) {
if (!response) { // Success
ReturnToAddOpportunity();
} else { // Invalid Form
$('section.ui-content-Override').html(response);
// Force jQuery Mobile to apply styles.
$('section.ui-content-Override').trigger('create');
// Force client side validation.
$.validator.unobtrusive.parse($('section.ui-content-Override'));
AddContactLoad();
$.mobile.loading('hide');
}
},
complete: function () {
},
error: function (xhr, status, error) {
// TODO - See if we need to handle errors here.
}
});
}
return false;
});
$('#btnCancel').on('click', function (e) {
e.preventDefault();
// See where add contact was called from.
var previousPage = $.cookie('cmdPreviousPage');
if (previousPage.indexOf("Detail") >= 0) {
ReturnToOpportunityDetails();
} else {
ReturnToAddOpportunity();
}
return false;
});
}
If I click the cancel button, that code is fired so I know this is working too. Here is my form code:
#using (Html.BeginForm("Add", "Contact", FormMethod.Post, new { #id = "frmAddContact" }))
{
#Html.ValidationSummary(true)
#Html.AntiForgeryToken()
-- Form Fields Here --
<div class="savecancel" >
<input type="submit" value="Save" data-mini="true", data-theme="b", data-inline="true" />
Cancel
</div>
}
As you can see the form is named frmAddContact and that is what the AddContactLoad() function is attaching the submit event to. To save my sole I cannot figure out why the form does not submit via the ajax post like every other form in the app. Am I missing some kind of initialization, I just don't know. If anyone can please help I'd really appreciate it!!
As it turns out, I had created a custom unobtrusive Ajax validator for a phone number then copied and pasted it to do the same with a zip code. Unfortunately in the process I forgot to rename a variable and thus an error was occurring in the validation script which caused the problem. In the mean time, if you're reading this, you might take a note of the code here and how to inject HTML into a page via Ajax and jQuery mobile. I've never found this in a book or on the web and it contains some very useful methodology and syntax. On the form submit the reason I'm checking for the empty response is I just return null from the controller to validate the form was valid and the save worked in which case I send them to a different HTML injection i.e. that page they originally came from. If null is not returned I inject that page with the HTML containing the original form and error markup so the user can make corrections then resubmit. I'm also calling a form load method that attaches handlers to the HTML once it's injected into the main page. Hope this helps somebody!

Backbone.js understanding: fetch and display with templating

I've read many tutorials and made a search on the .net... but still I'm in trouble with Backbone.js. This is my simple scenario:
A Rails application responds to a GET request with a JSON collection of objects.
I want to dynamically build a list of table-rows with Backbone collections, when DOM is ready. This is the code is confusing me:
HTML part:
<script type="text/template" id="tmplt-Page">
<td>{{=title}}</td>
<td>{{=description}}</td>
</script>
Backbone's script:
$(function(){
var Page = Backbone.Model.extend({});
var Pages = Backbone.Collection.extend({
model: Page,
url: '/pages'
});
var pages = new Pages([
{title: 'ProvA1', description: ''},
{title: 'ProvA2', description: ''}
]);
var PageView = Backbone.View.extend({
tagName: 'tr',
template: _.template($('#tmplt-Page').html()),
render: function() {
this.$el.append(this.template(this.model.toJSON()));
return this;
}
});
var AppView = Backbone.View.extend({
el: $("#results"),
initialize: function () {
_.bindAll(this, 'render');
pages.on('reset', this.render)
},
render: function() {
this.$el.empty();
pages.each( function( page ) {
var view = new PageView({
model : page
});
this.$el.append(view.render().el);
});
return this;
}
});
var appview = new AppView;
});
Nothing renders on the screen.
There seem to be 2 problems:
1) fetch() is asynchronous, so the code is executed before the end of the ajax round-trip.
2) If I manually load some objects into the collection, this piece of code "this.template(this.model.toJSON())" does not substitute jSON attributes
EDIT :
To use mustache tags I wrote this code before all:
First, as you said, fetch() is asynchronous, but it triggers the 'reset' event when it completes, so you should add this in AppView.initialize:
pages.on('reset', this.render)
Second, you never insert the HTML of PageView anywhere. Add this in AppView.render:
// at the beginning
var self = this;
// and in the forEach loop
self.$el.append(view.el);
Third, at the beginning of AppView.render, you should clear the content of this.$el.
EDIT:
You still had a couple issues:
You are using underscore templates with mustache tags ({{ }} -> <%= %>)
Missing var self = this in render
You are not calling appview.render() ! :)
Here's your code working on jsfiddle: http://jsfiddle.net/PkuqS/

Resources