I have a object called Index:
function Index() {
var self = this;
self.name = ko.observable("Kiwanax");
}
And I have a ViewModel like this:
function IndexViewModel() {
var self = this;
var index = new Index();
self.content = index;
self.default = index;
}
ko.applyBindings(new IndexViewModel());
//-------------------------------------------
<input type="text" data-bind="text: content.name" />
The point is: in some point, I want to reset my form to default values. It means change the current viewmodel values to the default variable values. But I'm not figuring out how to do this.
self.resetForm = function() {
// How to update the current content variable to default variable values?
// I think in something like that below:
self.content = self.default;
}
Thanks all!
The form doesn't display anything because you should use the value binding with inputs.
As for the default values, my suggestion is to make an extender:
ko.extenders.defaultValue = function(target, option){
target.reset = function(){
target(option);
}
return target;
}
And use it like this:
self.name = ko.observable("Kiwanax").extend({defaultValue:"defaultValue"});
To reset to default call:
self.name.reset();
Fiddle with all code: http://jsfiddle.net/25ECB/3/
EDIT: To control a lot of fields, you could use ko mapping and use the create option to add the extender, but I prefer the implementation below, because it allows for an easy resetAll (updated fiddle: http://jsfiddle.net/25ECB/6/).
function Index() {
var self = this;
var lotsOfProps = [
{
name:"name1",
value:"initialValue1",
},
{
name:"name2",
value:"initialValue2",
},
{
name:"name3",
value:"initialValue3",
}
];
ko.utils.arrayForEach(lotsOfProps, function(prop){
self[prop.name] = ko.observable(prop.value).extend({defaultValue:prop.value});
});
//self.name = ko.observable("Kiwanax").extend({defaultValue:"defaultValue"});
self.resetAll = function(){
ko.utils.arrayForEach(lotsOfProps, function(prop){
self[prop.name].reset();
})
}
}
function IndexViewModel() {
var self = this;
var index = new Index();
self.content = index;
self.resetForm = function() {
// How to update the current content variable to default variable values?
// I think in something like that below:
self.content.resetAll();
}
}
Use a simple js object with default values:
function Index(data) {
var self = this;
self.name = ko.observable(data.name);
}
function IndexViewModel() {
var self = this;
self.defaultData = {name: "Kiwanax"};
self.index = new Index(defaultData);
self.resetForm = function() {
self.index = new Index(defaultData);
}
}
When you call resetForm, you just recreated Index object with default data.
Related
I have a component which has a service Injected into it's constructor and I have a map function on array of objects. When I tried access my model inside map function it's returning undefined error.
Code:
export class StrategyComponent implements ComponentDefinition{
type = "component";
strategies : any[];
constructor(#Inject(GateDataModel) private gateDataModel){
//Updatedcode
EmitterService.get("event_name")
.subscribe(obj => {
this.buildStrategies(obj.strategies);
})
}
buildStrategies(_strategies){
this.strategies = _strategies;
}
selectStrategy(i){ //Function called on click from template
this.gateDataModel.strategyId = this.strategies[i].id;
this.strategies.map(function(_strategy, index){
this.gateDataModel.strategyId = _strategy.id; //Error Here
i === index ? _strategy.isSelected = true : _strategy.isSelected = false;
})
}
}
How can I access my model inside map function?
Thanks
As I mentioned in the comment, I'm pretty sure the problem is calling 'this.gateDataModel.strategyId' inside the call back. this cannot be resolved in that scope. You have two options:
Trap this outside like so:
selectStrategy(i){ //Function called on click from template
this.gateDataModel.strategyId = this.strategies[i].id;
var _this = this;
this.strategies.map(function(_strategy, index){
_this.gateDataModel.strategyId = _strategy.id; //Error Here
i === index ? _strategy.isSelected = true : _strategy.isSelected = false;
})
}
You can use a function pointer arrow function expression instead:
selectStrategy(i){ //Function called on click from template
this.gateDataModel.strategyId = this.strategies[i].id;
this.strategies.map((_strategy, index) => {
this.gateDataModel.strategyId = _strategy.id; //Error Here
i === index ? _strategy.isSelected = true : _strategy.isSelected = false;
}) // You might need to check my syntax
}
So I'm passing a custom class to my controller and it seems that the JsonResult is not properly passed.
What bothers me is that (also the fullcalendar wont read the json) the console.log which I have in my view prints the path to the function (wtf?) instead of what Json shoul return
This is my code:
public JsonResult GetCalendarEvents()
{
var eventList = BusinessLayer.Event.getAllEvents();
return Json(eventList.ToArray(), JsonRequestBehavior.AllowGet);
}
What kind of object has to be passed for this to work?
My evenList is of type List<Event> from here:
public static String ListToString(List<Event> evs)
{
String ret = "";
foreach (var ev in evs)
{
ret += ev.ToString() + "\n";
}
return ret;
}
public static List<Event> getAllEvents()
{
List<DataLayer.Event> dbEvents = DataApi.db.Event.ToList();
List<Event> returnEvents = new List<Event>();
foreach (DataLayer.Event oneEvent in dbEvents)
{
Event newEvent = new Event
{
ID = oneEvent.IDEvent,
userID = oneEvent.UserID,
projectID = oneEvent.ProjectID,
jobtypeID = oneEvent.JobTypeID,
taskID = oneEvent.TaskID,
ticketID = oneEvent.TicketID,
loccoID = oneEvent.LoccoID,
startTime = oneEvent.StartTime,
endTime = oneEvent.EndTime,
shiftFrom = oneEvent.ShiftFrom,
shiftTo = oneEvent.ShiftTo,
description = oneEvent.Description,
billable = oneEvent.Billable
};
returnEvents.Add(newEvent);
}
return returnEvents;
}
I tried displaying the events in fullcalendar:
$('#calendar').fullCalendar({
header: {
left: 'title',
center: '',
right: 'prev,next today basicDay,basicWeek,month',
},
//events: "/Calendar/GetEvents/", // not implemented
events: "#Url.Action("GetCalendarEvents/")",
and outputing the result to console:
console.log("#Url.Action("GetCalendarEvents/")");
but I get:
VM84 Index:83 /Calendar/GetCalendarEvents/
fullcalendar.min.js:6 Uncaught TypeError: Cannot read property 'hasTime' of undefined
It looks like you're missing some required fields. If you look at the documentation, title, start are required. Try setting these in the class to start with and build from that...
public static List<Event> getAllEvents()
{
List<DataLayer.Event> dbEvents = DataApi.db.Event.ToList();
List<Event> returnEvents = new List<Event>();
foreach (DataLayer.Event oneEvent in dbEvents)
{
Event newEvent = new Event
{
start = oneEvent.StartTime,
title = oneEvent.Description // you may need to add this to your Event class.
};
returnEvents.Add(newEvent);
}
return returnEvents;
}
Also, instead of using console to log the Json, use Fiddler or Chrome Advanced Tools
I'm building a site in Orchard that will have around 130 pages. We've setup a Navigation menu called "Main Menu" with all of our pages setup in a hierarchy (the example I'm showing is from my sandbox site and not our actual development site).
In my "AsideFirst" zone on our default widget layer, I have added a menu widget that references the above "Main Menu." The start level is set to 0, and the levels to display is set to 0. On the front end, using the shape tracer, I have created an alternate called "Parts.MenuWidget-AsideFirst.cshtml."
The menu renders just fine, however, I'm not sure where to start on modifying the core "Navigation" driver to allow me to display only the pages relative to the page that I'm on. For instance, if I'm on the page "Testing II" I'd like navigation that renders the following HTML:
<ul>
<li>Testing I</li>
<li>
Testing II
<ul>
<li></li>
</ul>
</li>
<li>Testing III
</ul>
The alternate that I'm using has the following code. This works if I'm within any of the top level sections, but not the deeper levels. The following code is not the Orchard way to do things, so I'd like to know how I should achieve this properly through drivers and handlers - especially since this isn't accomplishing what I need it to anyway.
#{
var navTag = Tag(Model, "nav");
navTag.AddCssClass("nav-sidebar");
#navTag.StartElement;
var ulTag = Tag(Model, "ul");
#ulTag.StartElement
// Model is Model.Menu from the layout (Layout.Menu)
var items = getSectionItems((IList<dynamic>)Enumerable.Cast<dynamic>(Model.Menu.Items));
// Add First and Last Classes
if (items.Any())
{
items[0].Classes.Add("first");
items[items.Count - 1].Classes.Add("last");
}
// List Items
foreach (var listModel in items)
{
// Current URL
string requestUrl = getRequestUrl();
string modelUrl = getModelUrl(listModel);
bool showMenu = false;
if (isActivePage(requestUrl, modelUrl))
{
listModel.Classes.Add("active");
showMenu = true;
}
if (showMenu)
{
// Sub Items
var listItems = Enumerable.Cast<dynamic>((System.Collections.IEnumerable)listModel);
if (listItems.Any())
{
listModel.Classes.Add("dropdown");
}
// List Tag
var liTag = Tag(listModel, "li");
#liTag.StartElement;
listModel.Metadata.Alternates.Clear();
listModel.Metadata.Type = "MenuItemLink";
// Top Level Nav Items
string className = System.Text.RegularExpressions.Regex.Replace(listModel.Href, "[^A-Za-z0-9-]", "");
className = className.Length > 0 ? className : "home";
#listModel.Text
if (listItems.Any())
{
<ul>
#DisplayChildren(listModel)
</ul>
}
#liTag.EndElement;
}
}
#ulTag.EndElement;
#navTag.EndElement;
}
#functions{
private IList<dynamic> getSectionItems(IList<dynamic> sectionItems)
{
return sectionItems;
}
private string getRequestUrl()
{
return Request.Path.Replace(Request.ApplicationPath, string.Empty).TrimEnd('/').ToUpperInvariant();
}
private string getModelUrl(dynamic listModel)
{
return listModel.Href.Replace(Request.ApplicationPath, string.Empty).TrimEnd('/').ToUpperInvariant();
}
private bool isActivePage(string requestUrl, string modelUrl)
{
if (requestUrl == modelUrl || (!string.IsNullOrEmpty(modelUrl) && requestUrl.StartsWith(modelUrl + "/")))
{
return true;
}
return false;
}
}
Updated
I've solved this using the following code. I was close, but I wish I still had a better solution. It solves this for up to 4 levels deep.
#{
var navTag = Tag(Model, "nav");
navTag.AddCssClass("nav-sidebar");
#navTag.StartElement;
var ulTag = Tag(Model, "ul");
#ulTag.StartElement
// Model is Model.Menu from the layout (Layout.Menu)
string requestUrl = getRequestUrl();
var menus = (IList<dynamic>)Enumerable.Cast<dynamic>(Model.Menu.Items);
var items = getSectionItems(requestUrl, menus);
// List Items
foreach (var listModel in items)
{
// Sub Items
var listItems = Enumerable.Cast<dynamic>((System.Collections.IEnumerable)listModel);
if (listItems.Any())
{
listModel.Classes.Add("nav-section");
}
// List Tag
var liTag = Tag(listModel, "li");
#liTag.StartElement;
listModel.Metadata.Alternates.Clear();
listModel.Metadata.Type = "MenuItemLink";
// Top Level Nav Items
string className = System.Text.RegularExpressions.Regex.Replace(listModel.Href, "[^A-Za-z0-9-]", "");
className = className.Length > 0 ? className : "home";
#listModel.Text
if (listItems.Any())
{
<ul>
#DisplayChildren(listModel)
</ul>
}
#liTag.EndElement;
}
#ulTag.EndElement;
#navTag.EndElement;
}
#functions{
private IList<dynamic> getSectionItems(string requestUrl, IList<dynamic> sectionItems1)
{
foreach (var sectionItem1 in sectionItems1)
{
if (getModelUrl(sectionItem1) == requestUrl)
return sectionItem1;
foreach (var sectionItem2 in sectionItem1)
{
if (getModelUrl(sectionItem2) == requestUrl)
return sectionItem2;
foreach (var sectionItem3 in sectionItem2)
{
if (getModelUrl(sectionItem3) == requestUrl)
return sectionItem3;
foreach (var sectionItem4 in sectionItem3)
{
if (getModelUrl(sectionItem4) == requestUrl)
return sectionItem4;
}
}
}
}
return sectionItems1;
}
private string getRequestUrl()
{
return Request.Path.Replace(Request.ApplicationPath, string.Empty).TrimEnd('/').ToUpperInvariant();
}
private string getModelUrl(dynamic listModel)
{
return listModel.Href.Replace(Request.ApplicationPath, string.Empty).TrimEnd('/').ToUpperInvariant();
}
private bool isActivePage(string requestUrl, string modelUrl)
{
if (requestUrl == modelUrl || (!string.IsNullOrEmpty(modelUrl) && requestUrl.StartsWith(modelUrl + "/")))
{
return true;
}
return false;
}
}
i am new to Knockout. I am trying out a scenario and i am not able to make it work. please help. I am using MVC4.
function ViewModel(data) {
var self = this;
this.Collection = ko.observable(data);
self.GetFilteredCollection = ko.computed(function () {
var filteredCollection = ko.utils.arrayFilter(self.Collection(), function (item) {
return item.IsSelected == true;
});
return filteredCollection;
});
self.FilteredCollectionCount = ko.computed(function () {
return self.GetFilteredCollection().length;
});
});
var collectionList = eval('<%= new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model.Collection) %>');
var VM = new ViewModel(collectionList);
ko.applyBindings(VM);
I have binded the IsSelected property to checkbox. Initially the IsSelected property will be set to false.
<span id="Span1" data-bind="text:$root.FilteredCollectionCount"></span>
I am always getting the Span value as 0 even if i select the checkbox. But i could see the Property IsSelected changed to true.
You need to make the IsSelected into a observable for the computed observable to be able to be notified when the value of IsSelected has changed
If it already is a observable then you need to change the code to
return item.IsSelected() == true;
I am working on a class for building drop down buttons dynamically. Here is excerpt one of my code (located in the Class constructor):
_button.onRollOver = function()
{
this.gotoAndStop("over");
TweenLite.to(this.options,0.2 * optionCount,{_y:mask._y, ease:Strong.easeOut, onComplete:detectMouse, onCompleteParams:[button]});
function detectMouse(button:MovieClip)
{
button.options.onMouseMove = function()
{
for (var option:String in this._parent.children)
{
if (this._parent.children[option].hitTest(_root._xmouse, _root._ymouse, true))
{
if (!this._parent.children[option].active) {
this._parent.children[option].clear();
drawOption(this._parent.children[option], "hover");
this._parent.children[option].active = true;
}
}
}
};
}
};
I am attempting to call on the function drawOption() which is inside the same class and looks like so:
private function drawOption(option:MovieClip, state:String)
{
trace("yo");
switch (state)
{
case "hover" :
var backgroundColour:Number = _shadow;
var textColour:Number = 0xffffff;
break;
default :
var backgroundColour:Number = _background;
var textColour:Number = _shadow;
break;
}
option._x = edgePadding;
option._y = 1 + edgePadding + (optionPadding * (option.index)) + (optionHeight * option.index);
option.beginFill(backgroundColour,100);
option.lineStyle(1,_border,100,true);
option.moveTo(0,0);
option.lineTo(_optionWidth,0);
option.lineTo(_optionWidth,optionHeight);
option.lineTo(0,optionHeight);
option.endFill();
var textfield:TextField = option.createTextField("string", option.getNextHighestDepth(), 20, 2, _optionWidth, optionHeight);
var format:TextFormat = new TextFormat();
format.bold = true;
format.size = fontSize;
format.font = "Arial";
format.color = textColour;
textfield.text = option.string;
textfield.setTextFormat(format);
}
But because I am trying to call from inside an onRollOver it seems that it is unable to recognise the Class methods. How would I go about accessing the function without making a duplicate of it (very messy, do not want!).
In AS2 I prefer to use the Delegate class to add functions to event handlers whilst maintaining control over the scope.
You implement it like this:
import mx.utils.Delegate;
//create method allows you to set the active scope, and a handler function
_button.onRollOver = Delegate.create(this,rollOverHandler);
function rollOverHander() {
// since the scope has shifted you need to use
// the instance name of the button
_button.gotoAndStop("over");
TweenLite.to(_button.options,0.2 * optionCount,{_y:mask._y, ease:Strong.easeOut, onComplete:detectMouse, onCompleteParams:[button]});
}
everything in the onrollover relates to the button which is rolled over, to access the outer functions, you would have to navigate to the outer class before calling the function in exactly the same way that you are accessing the outer variables, eg:
if the parent of the button contains the function:
this._parent.drawOption(....)
ContainerMC class:
class ContainerMC extends MovieClip{
function ContainerMC() {
// constructor code
trace("Container => Constructor Called");
}
function Init(){
trace("Container => Init Called");
this["button_mc"].onRollOver = function(){
trace(this._parent.SayHello());
}
}
function SayHello():String{
trace("Container => SayHello Called");
return "Hellooooo World";
}
}
I then have a movieclip in the library with the Class ContainerMC and the identitfier Container_mc, which is added to the stage by this line in the main timeline:
var Container = attachMovie("Container_mc","Container_mc",_root.getNextHighestDepth());
Container.Init();
Edit: added working sample