Binding data after promise - javascript

I have a table that contains a button that activates/deactivates users. When I click that button it makes a API call to change the status of the user. What I am having trouble with is performing a live update with the view after the API call. Currently, the only way I see the text switch is when I refresh the page.
Here is my Admin.html where the text on the button should switch between 'Active' and 'Inactive' when the button is clicked.
<tr ng-repeat="account in $ctrl.account">
<td>{{account.FirstName}}</td>
<td>{{account.LastName}}</td>
<td class="text-center">
<button class="btn btn-sm btn-active-status" ng-class="account.Active === true ? 'btn-info' : 'btn-danger'" ng-bind="account.Active === true ? 'Active' : 'Inactive'" ng-click="$ctrl.UpdateActiveStatus(account.Id, account.Active)"></button>
</td>
</tr>
Here is my AdminController.js
app.component('admin', {
templateUrl: 'Content/app/components/admin/Admin.html',
controller: AdminController,
bindings: {
accounts: '='
}
})
function AdminController(AccountService) {
this.$onInit = function () {
this.account = this.accounts;
}
this.UpdateActiveStatus = function (id, status) {
var data = {
Id: id,
Active: !status
};
AccountService.UpdateActiveStatus(data).then(function (response) {
AccountService.GetAccounts().then(function (data) {
this.account = data;
});
});
};
}

Here is the fix to my problem. Please let me know if there is a better way than this.
function AdminController(AccountService) {
var controller = this;
this.$onInit = function () {
controller.account = this.accounts;
}
this.UpdateActiveStatus = function (id, status) {
var data = {
Id: id,
Active: !status
};
AccountService.UpdateActiveStatus(data).then(function (data) {
for (var i = 0; i < controller.account.length; i++) {
if (controller.account[i].Id === data.Id) {
controller.account[i].Active = data.Active;
}
}
});
};
}

Related

Backbone subview is not rendered, "Uncaught ReferenceError: view is not defined" error returned

I am working on a site that uses Backbone.js, jQuery and I am trying to render a subview that has to display a description of the current page, loaded depending on a choice made from a dropdown menu. I searched for more info in the web but I am still stuck on this. Please help!
Here is the main view in which I have to load the description view:
const InquiryContentView = Backbone.View.extend(
{
el: $('#inquiryContent'),
events: {
'change #styles': 'renderTabs',
'click li.tab': 'renderTabPanel'
},
initialize: function () {
const view = this
this.inquiryContent = new InquiryContent
this.inquiryContent.fetch(
{
success: function () {
view.listenTo(view.inquiryContent, 'update', view.render)
view.render()
}
})
},
render: function () {
const data = []
this.inquiryContent.each(function (model) {
const value = {}
value.id = model.id
value.text = model.id
value.disabled = !model.get('active')
data.push(value)
})
data.unshift({id: 'none', text: 'Select One', disabled: true, selected: true})
this.$el.append('<h2 class="pageHeader">Inquiry Content</h2>')
this.$el.append('<select id="styles"></select>')
this.$stylesDropdown = $('#styles')
this.$stylesDropdown.select2(
{
data: data,
dropdownAutoWidth: true,
width: 'element',
minimumResultsForSearch: 10
}
)
this.$el.append('<div id="navWrapper"></div>')
this.$el.append('<div id="tNavigation"></div>')
this.$navWrapper = $('#navWrapper')
this.$tNavigation = $('#tNavigation')
this.$navWrapper.append(this.$tNavigation)
this.$el.append('<div id="editorDescription"></div>')
},
renderTabs: function (id) {
const style = this.inquiryContent.findWhere({id: id.currentTarget.value})
if (this.clearTabPanel()) {
this.clearTabs()
this.tabsView = new TabsView({style: style})
this.$tNavigation.append(this.tabsView.el)
}
},
renderTabPanel (e) {
const tabModel = this.tabsView.tabClicked(e.currentTarget.id)
if (tabModel && this.clearTabPanel()) {
this.tabPanel = new TabPanelView({model: tabModel})
this.$tNavigation.append(this.tabPanel.render().el)
}
},
clearTabs: function () {
if (this.tabsView !== undefined && this.tabsView !== null) {
this.tabsView.remove()
}
},
clearTabPanel: function () {
if (this.tabPanel !== undefined && this.tabPanel !== null) {
if (this.tabPanel.dataEditor !== undefined && this.tabPanel.dataEditor.unsavedChanges) {
if (!confirm('You have unsaved changes that will be lost if you leave the page. '
+ 'Are you sure you want to leave the page without saving your changes?')) {
return false
}
this.tabPanel.dataEditor.unsavedChanges = false
}
this.tabPanel.remove()
}
return true
}
}
)
I am trying to render the subview adding this method:
renderDescription () {
this.$editorDescription = $('#editorDescription')
this.descView = new DescView({model: this.model})
this.$editorDescription.append(this.descView)
this.$editorDescription.html(DescView.render().el)
}
It has to be rendered in a div element with id='editorDescription'
but I receive Uncaught ReferenceError: DescView is not defined
Here is how DescView is implemented:
window.DescView = Backbone.View.extend(
{
el: $('#editorDescription'),
initialize: function () {
_.bindAll(this, 'render')
this.render()
},
render: function () {
$('#editorDescriptionTemplate').tmpl(
{
description: this.model.get('description')})
.appendTo(this.el)
}
);
What am I doing wrong?
Your implementation of the DescView is incomplete. You are missing a bunch of closing braces and brackets. That's why it's undefined.

While uncheck the checkbox needs to reload the search item

I'm having the search column with checkbox along with folder names. when I click the checkbox of corresponding folder, it will show their items. As well as when I click on multiple checkbox it will show their corresponding items. But when I uncheck the folder, the corresponding items doesn't remove. So I need the hard reload or refresh when I check or uncheck the checkbox or need to clear the cache for every check or uncheck.
Here is my Code:
Checkbox: Core.component.Checkbox.extend({
click: function () {
var ret=null;
var nav = this.get("controller").get('selectedNavigator');
ret = this._super.apply(this, arguments);
var states=null;
Ember.run.schedule('sync', this, function () {
Ember.run.schedule('render', this, function () {
states = this.get('parentView.itemStates');
var values = Object.keys(states).filter(function (key) {
if(states[key]){
return states[key];}
else{return;}
});
if (values.length === 0) {
Core.Action('core:contentHome', {});
} else {
this.set('parentView.model.values',values);
nav.publish();
}
});
});
return ret;
}
}),
For the Publish:
publish: function () {
var currentResultSet = this.get('resultSet'),
ctl = this.get('controller'),
form = ctl.get('formModel'),
resultSet,
data = form.sleep(2000);
if (Object.keys(data).length === 0) {
Core.view.Menu.create({
anchor: $('*[data-class-name="Core.Tab.Content.Controller.NavigationRefresh"]'),
model: [
Core.model.Menu.Item.create({
label: "Please select something to search.",
icon: 'dialog_warning'
})
]
}).show();
return;
}
resultSet = form.send();
ctl.set('loadState', 'loading');
ctl.set('resultSet', Core.model.BlankResultSet.create({
loadState: 'loading',
tabContext: Ember.get(form, 'resultSet.tabContext')
}));
resultSet.fail(function (err) {
ctl.set('loadState', 'loaded');
console.log(currentResultSet);
ctl.set('resultSet', currentResultSet);
}).always(function () {
ctl.set('loadState', 'loaded');
});
},

getting main class object inside function without using arrow function

In my angular project, I am using datatable where I have row grouping and row callbacks.
datatable options
openPositionDatatableOptions = {
sDom: 'rt<"bottom"p>',
ajax: (data, callback, settings) => {
this.service.getOpenPositions()
.map(data => data.json().data).catch(this.handleError)
.subscribe(jsondata => {
this.openPositionsData = jsondata;
jsondata.forEach(element => {
if (element.side === 'SLD') {
element.openQuantity = '-' + element.openQuantity;
}
element['delta'] = 0;
element['pl'] = 0;
});
if (jsondata) {
callback({
aaData: jsondata
});
}
},
error => {
this.notifiicationAlert('Some Error Occured While Retrieving Positions Data', 'WARNING');
});
},
columns: [
{ data: 'account.brokerId' },
{ data: 'contract.localSymbol' },
{ data: 'openQuantity' },
{ data: 'delta' },
{ data: 'pl' },
{
data: null,
orderable: false,
defaultContent:
'<a class="fa fa-remove" style="color:#8B0000"></a>',
responsivePriority: 2
}
],
//Grouping By Row Logic
"columnDefs": [
{ "visible": false, "targets": 0 }
],
"order": [[0, 'asc']],
"drawCallback": function (settings) {
var api = this.api();
var rows = api.rows({ page: 'current' }).nodes();
var last = null;
api.column(0, { page: 'current' }).data().each(function(group, i) {
if (last !== group) {
$(rows).eq(i).before(
'<tr class="group"><td colspan="5"><div class="row"><div class="col-lg-6" style="text-align:left">' + group + '</div><div class="col-lg-6" style="text-align:right"><button class="datatableGroupingBtn btn btn-default btn-xs fa fa-remove" value='+group+'></button></div></div></td></tr>'
);
last = group;
}
});
// jQuery button click event
$(".datatableGroupingBtn").on('click',(value)=>{
var clickedRow = value.currentTarget.value;
});
},
//Grouping By Row Logic Ends
rowCallback: (row: Node, data: any | Object, index: number) => {
$('a', row).bind('click', () => {
this.service.closePosition(data.id).catch(this.handleError).subscribe(
res => {
if (res.status == 200) {
//TODO Re-implement this using web-socket
if ($.fn.DataTable.isDataTable(this.service.openPositionTableAlias)) {
const table = $(this.service.openPositionTableAlias).DataTable();
if (this.openPositionsData.length > 1) {
$('td', row)
.parents('tr')
.remove();
} else {
table.clear().draw();
}
this.notifiicationAlert('Position Closed Successfully', 'SUCCESS');
}
}
},
(error: Response) => {
this.notifiicationAlert('Some Problem While Closing The Position', 'WARNING');
}
);
});
return row;
}
};
In my datatable options, I have a drawCallback function inside I am grouping the rows. Inside the function, I also have a jquery click event over #datatableGroupingBtn
"drawCallback": function (settings) {
var api = this.api();
var rows = api.rows({ page: 'current' }).nodes();
var last = null;
api.column(0, { page: 'current' }).data().each(function(group, i) {
if (last !== group) {
$(rows).eq(i).before(
'<tr class="group"><td colspan="5"><div class="row"><div class="col-lg-6" style="text-align:left">' + group + '</div><div class="col-lg-6" style="text-align:right"><button class="datatableGroupingBtn btn btn-default btn-xs fa fa-remove" value='+group+'></button></div></div></td></tr>'
);
last = group;
}
});
// jQuery button click event
$(".datatableGroupingBtn").on('click',(value)=>{
var clickedRow = value.currentTarget.value;
});
}
Now my requirement is, I have to access the class level this that is My OrderComponent class object inside the jquery click event binding of #datatableGroupingBtn. I know that this can be done if I use arrow function over the drawCallback but if I use then other required functionalities won't work as you can see that I have used some properties using function() level this inside drawCallback function.
My component
import { NotificationService } from './../shared/utils/notification.service';
import { Global } from 'app/shared/global';
import { endponitConfig } from 'environments/endpoints';
import { Observable } from 'rxjs';
import { Http } from '#angular/http';
import { OrderService } from './order.service';
import { Component, OnInit, OnDestroy, AfterViewInit } from '#angular/core';
import { Router } from '#angular/router';
declare var $: any;
#Component({
selector: 'app-order',
templateUrl: './order.component.html',
styleUrls: ['./order.component.css']
})
export class OrderComponent {
openPositionsData: any;
openOrdersData: any;
openPositionDatatableOptions = {
sDom: 'rt<"bottom"p>',
ajax: (data, callback, settings) => {
this.service.getOpenPositions()
.map(data => data.json().data).catch(this.handleError)
.subscribe(jsondata => {
this.openPositionsData = jsondata;
jsondata.forEach(element => {
if (element.side === 'SLD') {
element.openQuantity = '-' + element.openQuantity;
}
element['delta'] = 0;
element['pl'] = 0;
});
if (jsondata) {
callback({
aaData: jsondata
});
}
},
error => {
this.notifiicationAlert('Some Error Occured While Retrieving Positions Data', 'WARNING');
});
},
columns: [
{ data: 'account.brokerId' },
{ data: 'contract.localSymbol' },
{ data: 'openQuantity' },
{ data: 'delta' },
{ data: 'pl' },
{
data: null,
orderable: false,
defaultContent:
'<a class="fa fa-remove" style="color:#8B0000"></a>',
responsivePriority: 2
}
],
//Grouping By Row Logic
"columnDefs": [
{ "visible": false, "targets": 0 }
],
"order": [[0, 'asc']],
"drawCallback": function (settings) {
var api = this.api();
var rows = api.rows({ page: 'current' }).nodes();
var last = null;
api.column(0, { page: 'current' }).data().each(function(group, i) {
if (last !== group) {
$(rows).eq(i).before(
'<tr class="group"><td colspan="5"><div class="row"><div class="col-lg-6" style="text-align:left">' + group + '</div><div class="col-lg-6" style="text-align:right"><button class="datatableGroupingBtn btn btn-default btn-xs fa fa-remove" value='+group+'></button></div></div></td></tr>'
);
last = group;
}
});
// jQuery button click event
$(".datatableGroupingBtn").on('click',(value)=>{
var clickedRow = value.currentTarget.value;
});
},
//Grouping By Row Logic Ends
rowCallback: (row: Node, data: any | Object, index: number) => {
$('a', row).bind('click', () => {
this.service.closePosition(data.id).catch(this.handleError).subscribe(
res => {
if (res.status == 200) {
//TODO Re-implement this using web-socket
if ($.fn.DataTable.isDataTable(this.service.openPositionTableAlias)) {
const table = $(this.service.openPositionTableAlias).DataTable();
if (this.openPositionsData.length > 1) {
$('td', row)
.parents('tr')
.remove();
} else {
table.clear().draw();
}
this.notifiicationAlert('Position Closed Successfully', 'SUCCESS');
}
}
},
(error: Response) => {
this.notifiicationAlert('Some Problem While Closing The Position', 'WARNING');
}
);
});
return row;
}
};
constructor(private http : Http, private service : OrderService){
this.http.get(Global.serviceUrl).subscribe(response=>{
this.openPositionsData = response.json().data;
})
}
}
Assign your openPositionDatatableOptions in the constructor, after declaring a self variable
openPositionDatatableOptions : any;
constructor()
{
const self = this;
this.openPositionDatatableOptions = {
//....
"drawCallback": function (settings) {
//....
// jQuery button click event
$(".datatableGroupingBtn").on('click',(value)=>{
var clickedRow = value.currentTarget.value;
console.log(self);//<=== self is your class instance
});
},
}
Inside the method your jQuery event binding is, declare a variable like so
let self = this;
now you should be able to use this variable in your jquery click event binding

ng-hide & ng-show in AngularJS

Using AngularJS I want to show and hide the data related with particular id in the toggle way.
My JSON Data format is like:
$scope.things = [{
id: 1,
data: 'One',
shown: true
}, {
id: 2,
data: 'Two',
shown: false
}, {
id: 3,
data: 'Three',
shown: true
}, ];
What I want is when click on id-1 It will show text One and Hide the others, when click on id-2 will show text Two and hide others and so on.
Here is the fiddle what I tried : jsfiddle : Demo Link
i updated your code
$scope.flipMode = function (id) {
$scope.things.forEach(function (thing) {
if(id == thing.id){
thing.shown = true;
}
else{
thing.shown = false;
}
})
};
{{thing.id}}
here is the working fiddle
It should work
$scope.flipMode = function (id) {
$scope.things.forEach(function (thing) {
if(thing.id === id) {
thing.shown = true;
return;
}
thing.shown = false;
})
};
<div ng-repeat="thing in things">
{{thing.id}}
</div>
Forked working solution: http://jsfiddle.net/nypmmkrh/
Change your scope function:
$scope.flipMode = function (id) {
$scope.things.forEach(function(thing) {
if(thing.id == id) {
thing.shown = true;
} else {
thing.shown = false;
}
});
};
And pass the id in the view:
{{thing.id}}

Jquery Context Menu ajax fetch menu items

I have a jquery context menu on my landing page where I have hardcode menu items. Now I want to get the menu items from server. Basically the idea is to show file names in a specified directory in the context menu list and open that file when user clicks it...
This is so far I have reached..
***UPDATE***
C# code
[HttpPost]
public JsonResult GetHelpFiles()
{
List<Manuals> manuals = null;
var filesPath = Server.MapPath(#"\HelpManuals");
var standardPath = new DirectoryInfo(filesPath);
if (standardPath.GetFiles().Any())
{
manuals = standardPath.GetFiles().Select(x => new Manuals
{
Name = GetFileNamewithoutExtension(x.Name),
Path = x.Name
}).ToList();
}
return Json(manuals, JsonRequestBehavior.AllowGet);
}
private string GetFileNamewithoutExtension(string filename)
{
var extension = Path.GetExtension(filename);
return filename.Substring(0, filename.Length - extension.Length);
}
JavaScript Code
$.post("/Home/GetHelpFiles", function (data) {
$.contextMenu({
selector: '#helpIcon',
trigger: 'hover',
delay: 300,
build: function($trigger, e) {
var options = {
callback: function(key) {
window.open("/HelpManuals/" + key);
},
items: {}
};
$.each(data, function (item, index) {
console.log("display name:" + index.Name);
console.log("File Path:" + index.Path);
options.items[item.Value] = {
name: index.Name,
key: index.Path
}
});
}
});
});
Thanks to Matt. Now, the build function gets fire on hover.. but im getting illegal invocation... and when iterating through json result, index.Name and this.Name gives correct result. But item.Name doesn't give anything..
to add items to the context menu dynamically you need to make a couple changes
$.contextMenu({
selector: '#helpIcon',
trigger: 'hover',
delay: 300,
build: function($trigger, e){
var options = {
callback: function (key) {
var manual;
if (key == "adminComp") {
manual = "AdminCompanion.pdf";
} else {
manual = "TeacherCompanion.pdf";
}
window.open("/HelpManuals/" + manual);
},
items: {}
}
//how to populate from model
#foreach(var temp in Model.FileList){
<text>
options.items[temp.Value] = {
name: temp.Name,
icon: 'open'
}
</text>
}
//should be able to do an ajax call here but I believe this will be called
//every time the context is triggered which may cause performance issues
$.ajax({
url: '#Url.Action("Action", "Controller")',
type: 'get',
cache: false,
async: true,
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (_result) {
if (_result.Success) {
$.each(_result, function(item, index){
options.items[item.Value] = {
name: item.Name,
icon: 'open'
}
});
}
});
return options;
}
});
so you use build and inside of that define options and put your callback in there. The items defined in there is empty and is populated in the build dynamically. We build our list off of what is passed through the model but I believe you can put the ajax call in the build like I have shown above. Hopefully this will get you on the right track at least.
I solved this problem the following way.
On a user-triggered right-click I return false in the build-function. This will prevent the context-menu from opening. Instead of opeing the context-menu I start an ajax-call to the server to get the contextMenu-entries.
When the ajax-call finishes successfully I create the items and save the items on the $trigger in a data-property.
After saving the menuItems in the data-property I open the context-menu manually.
When the build-function is executed again, I get the items from the data-property.
$.contextMenu({
build: function ($trigger, e)
{
// check if the menu-items have been saved in the previous call
if ($trigger.data("contextMenuItems") != null)
{
// get options from $trigger
var options = $trigger.data("contextMenuItems");
// clear $trigger.data("contextMenuItems"),
// so that menuitems are gotten next time user does a rightclick
// from the server again.
$trigger.data("contextMenuItems", null);
return options;
}
else
{
var options = {
callback: function (key)
{
alert(key);
},
items: {}
};
$.ajax({
url: "GetMenuItemsFromServer",
success: function (response, status, xhr)
{
// for each menu-item returned from the server
for (var i = 0; i < response.length; i++)
{
var ri = response[i];
// save the menu-item from the server in the options.items object
options.items[ri.id] = ri;
}
// save the options on the table-row;
$trigger.data("contextMenuItems", options);
// open the context-menu (reopen)
$trigger.contextMenu();
},
error: function (response, status, xhr)
{
if (xhr instanceof Error)
{
alert(xhr);
}
else
{
alert($($.parseHTML(response.responseText)).find("h2").text());
}
}
});
// This return false here is important
return false;
}
});
I have finally found a better solution after reading jquery context menu documentation, thoroughly..
C# CODE
public JsonResult GetHelpFiles()
{
List<Manuals> manuals = null;
var filesPath = Server.MapPath(#"\HelpManuals");
var standardPath = new DirectoryInfo(filesPath);
if (standardPath.GetFiles().Any())
{
manuals = standardPath.GetFiles().Select(x => new Manuals
{
Name = GetFileNamewithoutExtension(x.Name),
Path = x.Name
}).ToList();
}
return Json(manuals, JsonRequestBehavior.AllowGet);
}
HTML 5
<div id="dynamicMenu">
<menu id="html5menu" type="context" style="display: none"></menu>
</div>
JavaScript Code
$.post("/Home/GetHelpFiles", function (data) {
$.each(data, function (index, item) {
var e = '<command label="' + item.Name + '" id ="' + item.Path + '"></command>';
$("#html5menu").append(e);
});
$.contextMenu({
selector: '#helpIcon',
trigger: 'hover',
delay: 300,
items: $.contextMenu.fromMenu($('#html5menu'))
});
});
$("#dynamicMenu").on("click", "menu command", function () {
var link = $(this).attr('id');
window.open("/HelpManuals/" + link);
});
Here's my solution using deferred, important to know that this feature is supported for sub-menus only
$(function () {
$.contextMenu({
selector: '.SomeClass',
build: function ($trigger, e) {
var options = {
callback: function (key, options) {
// some call back
},
items: JSON.parse($trigger.attr('data-storage')) //this is initial static menu from HTML attribute you can use any static menu here
};
options.items['Reservations'] = {
name: $trigger.attr('data-reservations'),
icon: "checkmark",
items: loadItems($trigger) // this is AJAX loaded submenu
};
return options;
}
});
});
// Now this function loads submenu items in my case server responds with 'Reservations' object
var loadItems = function ($trigger) {
var dfd = jQuery.Deferred();
$.ajax({
type: "post",
url: "/ajax.php",
cache: false,
data: {
// request parameters are not importaint here use whatever you need to get data from your server
},
success: function (data) {
dfd.resolve(data.Reservations);
}
});
return dfd.promise();
};

Categories

Resources