WinJS Two way Binding returning undefined - data-binding

I am new to window8 development, I am basically trying to implement this link
http://msdn.microsoft.com/en-us/magazine/jj651576.aspx
I am using the view model as in figure8 in the link example, but I am unable to display the data, it shows the undefine, but if I only give one element of array I am able to bind it.
My UI is
<body>
<section aria-label="Main content" role="main">
<!-- display each person -->
<div id="nameLabel">Name</div>
<input id="name" readonly="true" type="text" data-win-bind="value: name" />
<div id="ageLabel">Age</div>
<input id="age" readonly="true" type="text" data-win-bind="value: age" />
<div id="colorLabel">Favorite Color</div>
<div id="color" data-win-bind="style.backgroundColor:favoriteColor"></div>
<div id="buttons">
<button id="previousButton"></button>
<button id="birthdayButton"></button>
<button id="nextButton"></button>
</div>
</section>
</body>
and the JavaScript contains
var people = [
// Notify binding listeners when these objects change
WinJS.Binding.as({ name: "John", age: 18, favoriteColor: "red" }),
WinJS.Binding.as({ name: "Tom", age: 16, favoriteColor: "green" }),
WinJS.Binding.as({ name: "Chris", age: 42, favoriteColor: "blue" }),
];
// Bind the current person to the HTML elements in the section
var section = document.querySelector("section[role=main]");
var current = 0;
var viewModel = WinJS.Binding.as({ person: people[current+1] });
WinJS.Binding.processAll(section, viewModel);
nextButton.onclick = function () {
current = (people.length + current + 1) % people.length;
viewModel.person = people[current];
};
This is the result:
Please help me to bind the UI with data model. Thanks in advance.

The problem happens because you've double wrapped a person with a WinJS.Binding. When you did that, you need to change the property path to:
data-win-bind="value: person.name"
When you created the viewModel property, it created a new property containing the actual person instance:
var viewModel = WinJS.Binding.as({ person: people[current+1] });
Also, note that there isn't two-way binding in WinJs.

Related

Calling Meteor methods in React components

Currently I'm working on a project based on Meteor as back end and React as front end. I really enjoyed simplicity untill I removed insecure package and have to deal with Meteor methods. Right now I need to perform a basic insert operation and I'm just stucked!
I have a form as component (in case eventually I'd like to use this form not only for inserting items but for editing those items as well) and here's my code for this form:
AddItemForm = React.createClass({
propTypes: {
submitAction: React.PropTypes.func.isRequired
},
getDefaultProps() {
return {
submitButtonLabel: "Add Item"
};
},
render() {
return (
<div className="row">
<form onSubmit={this.submitAction} className="col s12">
<div className="row">
<div className="input-field col s6">
<input
id="name"
placeholder="What"
type="text"
/>
</div>
<div className="input-field col s6">
<input
placeholder="Amount"
id="amount"
type="text"
/>
</div>
</div>
<div className="row">
<div className="input-field col s12">
<textarea
placeholder="Description"
id="description"
className="materialize-textarea">
</textarea>
</div>
</div>
<div className="row center">
<button className="btn waves-effect waves-light" type="submit">{this.props.submitButtonLabel}</button>
</div>
</form>
</div>
);
}
});
This chunk of code is used as a form component, I have a prop submitAction which I use in let's say add view:
AddItem = React.createClass({
handleSubmit(event) {
event.preventDefault();
const
name = $('#name').val(),
amount = $('#amount').val(),
description = $('#description').val();
Items.insert(
{
name: name,
range: range,
description: description,
createdAt: new Date(),
ownerId: Meteor.userId()
},
function(error) {
if (error) {
console.log("error");
} else {
FlowRouter.go('items');
};
}
);
},
render() {
return (
<div className="row">
<h1 className="center">Add Item</h1>
<AddItemForm
submitButtonLabel="Add Event"
submitAction={this.handleSubmit}
/>
</div>
);
}
});
As you can see I directly grab values by IDs then perform insert operation which works absolutely correct, I can even get this data displayed.
So now I have to remove insecure package and rebuild the whole operation stack using methods, where I actually stucked.
As I understand all I should do is to grab same data and after that perform Meteor.call, but I don't know how to pass this data correctly into current method call. I tried considering this data right in the method's body which doesn't work (I used the same const set as in AddItem view). Correct me if I'm wrong, but I don't think this method knows something about where I took the data (or may be I don't really get Meteor's method workflow), so by this moment I ended up with this code as my insert method:
Meteor.methods({
addItem() {
Items.insert({
name: name,
amount: amount,
description: description,
createdAt: new Date(),
ownerId: Meteor.userId()
});
}
});
and this is how I changed my handleSubmit function:
handleSubmit(event) {
event.preventDefault();
const
name = $('#name').val(),
amount = $('#amount').val(),
description = $('#description').val();
Meteor.call('addItem');
},
Also I tried declaring method like this:
'addItem': function() {
Items.insert({
// same code
});
}
but it also didn't work for me.
Again, as I understand the problem isn't about data itself, as I wrote before it works just right with insecure package, the problem is how the heck should I get this data on the server first and right after that pass this to the client using methods (also console gives no even warnings and right after I submit the form, the page reloads)?
I've already seen some tutorials and articles in the web and didn't find desicion, hope to get help here.
You can add your data as parameters in your Meteor call function. You can also add a callback function to check on the success of the call.
handleSubmit(event) {
event.preventDefault();
const
name = $('#name').val(),
amount = $('#amount').val(),
description = $('#description').val();
Meteor.call('addItem', name, amount, description, function(err, res) {
if (err){
console.log(JSON.stringify(err,null,2))
}else{
console.log(res, "success!")
}
});
},
In your Meteor methods:
Meteor.methods({
addItem(name, amount, description) {
var Added = Items.insert({
name: name,
amount: amount,
description: description,
createdAt: new Date(),
ownerId: Meteor.userId()
});
return Added
}
});

Components inside partials

How can Ractive Components live inside partials?
I have a FormInput Component
<FormInput type="text" label="Please enter name" value="{{John Doe}}"/>
which translates to
<div>
{{label}}: <input type="{{type}}" value="{{value}}">
</div>
There is also another component Modal
<div>
{{>modalContents}}
</div>
When I create a Modal component with
modalContents:'<FormInput type="text" label="Please enter name" value="{{John Doe}}"/>'
the component isn't rendered at all, probably because ractive thinks it is just text. I know, I am missing something here... Is there a way to make it actually parse the component?
*Note: examples are simplified
This does work, but you need to make sure that the FormInput component is registered. One way is to register it globally...
Ractive.components.FormInput = FormInput;
...but you can also register it when creating a new instance:
var FormInput = Ractive.extend({
template: '<div>{{label}}: <input type="{{type}}" value="{{value}}"></div>'
});
var Modal = Ractive.extend({
template: '<div>{{>modalContents}}</div>'
});
var modal = new Modal({
el: 'body',
partials: {
modalContents: '<FormInput type="text" label="Please enter name" value="John Doe"/>'
},
// register the component here
components: { FormInput: FormInput }
});
There is a small syntax error in your example which may be relevant – it should be John Doe, not {{John Doe}}.
Demo here: http://jsfiddle.net/rich_harris/80w8o1bu/

Add items to select list on the client side in MVC 5 ASP

I'm trying to learn more about MVC 5 so I'm writing a bloging site for myself to learn more as I go.
I have set up a select list for tags and would like to be able to add new tags from the create blog entry page rather than having to remember to set the tags up before creating a new post. I'm thinking down the lines of a "Add Tag" button which displays a bootstrap modal window where the user can add a new tag.
Here is my controller action:
public ViewResult CreateBlogPost()
{
CreateEditBlogViewModel viewModel = new CreateEditBlogViewModel();
viewModel.BlogPost = new Core.BlogPost();
viewModel.BlogPost.ShortBody = "<p>Something short and sweet to describe the post</p>";
viewModel.BlogPost.Body = "<p>Enter something blog worthy here...</p>";
viewModel.Tags = new SelectList(_blogRepo.BlogTags(), "Id", "Name");
viewModel.Categories = new SelectList(_blogRepo.BlogCategories(), "Id", "Name");
return View(viewModel);
}
And here is the HTML in the view:
<div class="row">
<div class="form-group">
#Html.LabelFor(m => m.BlogPost.Tags, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.ListBoxFor(m => m.SelectedTags, Model.Tags, new { #class = "form-control chosen-select", #data_placeholder = "Start typing to see a list of tags" })
</div>
</div>
</div>
<div class="row">
<!-- Button trigger modal -->
<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#tagModal">
Add Tag
</button>
</div>
Here is my partial view for the modal window:
#using (Html.BeginForm("SaveTag", "Home", FormMethod.Post, new { id = "tag-form" }))
{
#Html.AntiForgeryToken()
<!-- Modal -->
<div class="modal fade" id="tagModal" tabindex="-1" role="dialog" aria-labelledby="tagModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="tagModalLabel">Enter a name for a new tag</h4>
</div>
<div class="modal-body">
<input type="text" id="Name" placeholder="Enter a new tag name" />
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
<button type="submit" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
}
Is it possible to add a tag on the client side, persist it into the db and then add it to my tags select list without refreshing the page?
PS: FYI I'm using the Chosen multi-select from here.
#section scripts {
<script type="text/javascript" src="~/Scripts/chosen.jquery.min.js"></script>
<script type="text/javascript">
$(".chosen-select").chosen()
</script>
}
EDIT: I have updated the question with all the code that makes the view give the user the modal window to enter a new tag name. I'm just not sure how to post without navigating away from the page so I'm guessing some sort of Ajax post is required. And then what to do with the data that is returned from that post. How do I then add that new persisted record to the select list?
I know the tag isn't passing to the controller method as it's not bound to any sort of model but being as I'm using a view model on the parent view, I'm not sure how I would handle that here either.
In order to dynamically add a new BlogTag in the view you will need to post the new tag Name using ajax, to a controller method that saves the BlogTag and returns its new ID value. Your controller method would be something like
[HttpPost]
public JsonResult CreateTag(string name)
{
BlogTag tag = new BlogTag(){ Name = name };
db.BlogTags.Add(tag);
db.SaveChanges();
return Json(tag.ID);
// If the above code could result in an error/exception, catch it and return
// return Json(null);
}
Then in the view, handle the dialogs submit button to post the value and update the tag list
var url = '#Url.Action("CreateTag")';
var tagList = $('#SelectedTags');
$('#tag-form').submit(function() {
var tagName = $('#Name').val();
$.post(url, { name: tagName }, function(id) {
if (id) {
// add the new tag to the list box
tagList.append($('<option></option>').val(id).text($('#Name').val()));
// trigger the chosen update
tagList.trigger("chosen:updated");
} else {
// Oops - display an error message?
}
}).fail(function (result) {
// Oops - display an error message?
});
return false; // cancel the default submit
});
Side note: I would recommend that you create a view model for BlogTagVM (containing a property for the Name with validation attributes) and an associated partial view (say _AddBlogTag.cshtml) that generates the dialog html, so that in the main view you can use #Html.Partial("_AddBlogTag", new BlogTagVM()) which will allow you to use the strongly typed html helpers, and to include client side validation.
Note also that nested <form> elements are invalid html so ensure that html for the dialog is outside the main <form> tag for the view.
I am doing something similar, I think it might help. In my case, I'm "moving" values from one list to another (from "available" to "used") and then saving the values of the "used" list. Anyway, in the controller, the "used" list shows up as an array of strings. Here's my code:
public ActionResult PinchHit(FormCollection form, LineupViewModel lvm, String[] UsedPlayers)
{
[Snip]
if (ModelState.IsValid && lineupResults.IsValid)
{
[Snip]
foreach (String usedID in UsedPlayers)
{
gameState.HomeUsedPlayersIDs.Add(Convert.ToInt32(usedID));
}
uow.Repository<GameState>().Update(gameState);
uow.SaveChanges();
return RedirectToAction("Index", "GameSummary");
}
[Snip]
return View(lvm2);
}
Hope that helps.
Per my comment:
Here is an AJAX call-back mechanism I used to retrieve data from the database without reloading the page, you could use it to save data to the database instead.
<script type="text/javascript">
function getPositions(id, control) {
$.ajax({
url: "#Url.Action("GetPositions", "Lineup")",
data:
{
id: id
},
dataType: "json",
type: "POST",
error: function () {
alert("An error occurred.");
},
success: function (data) {
$(control).html("");
$.each(data, function (i, item) {
$(control).append("<option value=\"" + item.Value + "\">" + item.Text + "</option>");
}
);
}
});
}
</script>
then in the controller:
[HttpPost]
public ActionResult GetPositions(int id)
{
Player player = uow.Repository<Player>().GetById(id);
if (player == null)
{
return (null);
}
List<SelectListItem> positionList = new SelectList(player.Positions, "ID", "ShortName").ToList();
return Json(positionList);
}
Pretty standard stuff really.

Pre populate action form Alfresco share

I have an action which is showing a form for some user input. The inputs are plain text field. I wonder how can I pre fill the input field.
All the tutorials and blog posts I found are quite old and all of them are taking into account only one field. It is my understanding that I need a custom .ftl with a call to a web script in it.
<field id="myprop">
<control template="/org/alfresco/components/form/controls/mycustomfield.ftl"/>
</field>
The problem in my case is that I will end up doing at least six call to the same web script. Because that's the number of fields I currently have in my form.
Well I guess it could be implemented by using a form filter as well. Maybe not the nicest solution, but it should get the job done. https://wiki.alfresco.com/wiki/Forms_Developer_Guide#Form_Filter
There is only one better way... You don't need to use Share Form Engine. Take a look at "create site" dialog, this form doesn't use share form engine
You need to create custom share component that will return form with filled parameters and initialize this form in your front-end js that is executed while clicking on the action.
You can add new component to Share by the following way:
1) Create new descriptor my-form.get.desc.xml in web-extension/site-webscripts/com/pizdez/form
<webscript>
<shortname>my-form</shortname>
<description>Get HTML form</description>
<url>/pizdec/components/form</url>
</webscript>
2) Create new controller my-form.get.js in the same folder where you can call alfresco to get all needed information
var connector = remote.connect("alfresco");
var response = connector.get("/my/alfresco/webscript");
if (response.status == 200)
{
// Create javascript objects from the repo response
var obj = eval('(' + response + ')');
if (obj)
{
model.param1 = obj.param1;
}
}
3) Create ftl template my-form.get.html.ftl in the same folder
<#markup id="css" >
<#-- CSS Dependencies -->
<#link href="${url.context}/res/components/form/my.css" />
</#>
<#markup id="js">
<#script src="${url.context}/res/components/form/my.js" />
</#>
<#markup id="widgets">
<#createWidgets/>
</#>
<#markup id="html">
<#uniqueIdDiv>
<#assign el=args.htmlid?html>
<div id="${el}-dialog">
<div class="hd">TITLE</div>
<div class="bd">
<form id="${el}-form" method="POST" action="">
<div class="yui-gd">
<div class="yui-u first"><label for="${el}-title">Title:</label></div>
<div class="yui-u"><input id="${el}-title" type="text" name="title" tabindex="0" maxlength="255"/> *
</div>
</div>
<div class="yui-gd">
<div class="yui-u first"><label for="${el}-param1">Param1:</label></div>
<div class="yui-u"><input id="${el}-param1" type="text" name="title" tabindex="0" maxlength="255" value="${param1}"/> *
</div>
</div>
<div class="bdft">
<input type="submit" id="${el}-ok-button" value="${msg("button.ok")}" tabindex="0"/>
<input type="button" id="${el}-cancel-button" value="${msg("button.cancel")}" tabindex="0"/>
</div>
</form>
</div>
</div>
</#>
</#>
4) After that you need to get this component from ui js
var myForm = new Alfresco.module.SimpleDialog(this.id + "-dialog");
myForm.setOptions(
{
width: "50em",
templateUrl: Alfresco.constants.URL_SERVICECONTEXT + "/pizdec/components/form",
actionUrl: null,
destroyOnHide: true,
doBeforeDialogShow:
{
fn: doBeforeDialogShow,
scope: this
},
onSuccess:
{
fn: function (response)
{
},
scope: this
},
onFailure:
{
fn: function(response)
{
},
scope: this
}
}).show();
I just wanted to show you direction to research

learning AngularJs : ng-model does not binding into View

I am very new to angularJS and you can say that this is my first day using angularJS.
it seems silly BUt i am trying to do some basic stuff which is not working somehow.
I have a text box in which if you enter 1234, Count should be 555 OR if you enter any number it should be 550 and i am putting 1234 on page load so it is showing me 555 BUT when i change value in textbox, Count is not changing.
<div ng-app>
<div ng-controller="prCtrl">
Enter Product ID to get the reviews details
<input type="number" ng-model="productId" required />
<br />
Total Review Count = {{ Count }}
</div>
</div>
function prCtrl($scope,$http) {
$scope.productId = 1234;
if ($scope.productId === 1234) {
$scope.Count = 555;
} else {
$scope.Count = 550;
}
}
how can i change {{ Count }} depending on the value entered in textbox.
thanks
An option would be to subscribe to the model change and carry out your logic there:
Controller:
function prCtrl($scope,$http) {
$scope.productId = 1234;
$scope.$watch('productId', function(newValue, oldValue){
if (newValue === 1234) {
$scope.Count = 555;
} else {
$scope.Count = 550;
}
});
}
View:
<div ng-app>
<div ng-controller="prCtrl">
Enter Product ID to get the reviews details
<input type="number" ng-model="productId" required />
<br />
Total Review Count = {{ Count }}
</div>
</div>
I have tested that, and it appears to do what you want.
And a final note - you mention you are new to angular - I would highly recommend egghead.io 's sessions on AngularJS ( https://egghead.io/lessons ). They are good at getting you up to speed with AngularJS :)
Alternatively you can use a function, without watching the value using $watch
function prCtrl($scope,$http) {
$scope.productId = 1234;
$scope.getCount = function() {
if ($scope.productId === 1234) {
return 555;
} else {
return 550;
}
}
}
view:
<div ng-app>
<div ng-controller="prCtrl">
Enter Product ID to get the reviews details
<input type="number" ng-model="productId" required />
<br />
Total Review Count = {{ getCount() }} // replaced with function call
</div>
</div>
This function gets called when ever a model is changed in the scope, so it will always update your value

Resources