Build CRUD apps in fewer lines of code.

Overview

CanJS

SauceLabs Test Status

Join our Slack Join our Discourse npm version Build Status Greenkeeper badge

CanJS is a collection of client-side JavaScript architectural libraries.

Web Components

CanJS’s StacheElement allows you to create Web Components with observable properties and live-bound templates.

class Counter extends StacheElement {
	static view = `
		Count: <span>{{ this.count }}</span>
		<button on:click="this.increment()">+1</button>
	`;

	static props = {
		count: 0
	};

	increment() {
		this.count++;
	}
}
customElements.define("my-counter", Counter);

Model layer

Components shouldn’t be concerned with how data is fetched, updated, or cached.

CanJS provides the right abstractions for your model code to be cleanly separated from your UI code. Learn more…

Promises in templates

CanJS’s stache templating language can directly read the state and values from Promises.

No need to write any extra code to determine whether a Promise is pending, resolved, or rejected. Learn more…

{{# if(this.promise.isPending) }}
  Loading…
{{/ if }}
{{# if(this.promise.isRejected) }}
  Error: {{ this.promise.reason }}
{{/ if }}
{{# if(this.promise.isResolved) }}
  Result: {{ this.promise.value }}
{{/ if }}

Real-time list updating

After data is created, updated, or destroyed, CanJS automatically updates your lists for you.

Filtering and sorting are preserved, so you don’t have to manually update your lists or fetch the same data again. Learn more…

Getting Started

Ready to get started? See the Setting Up CanJS, API Docs and Guides pages.

Support / Contributing

Before you make an issue, please read our Contributing guide.

You can find the core team on Slack.

Release History

See Releases.

License

MIT License.

Comments
  • Condition (helper) inside can-EVENT doesn't work

    Condition (helper) inside can-EVENT doesn't work

    in latest minor pre 2.3 code:

    <div can-click="{{#if canShowPopover}}togglePopover{{/if}}"></div>
    

    causes an error:

    Uncaught TypeError: Cannot read property 'compile' of undefined .../node_modules/can/view/stache/text_section.js 29 TypeError: Cannot read property 'compile' of undefined
    

    it works in 2.2.6

    bug fixed in branch 
    opened by wclr 42
  • Change syntax for passing in template objects to Components to use `{}`

    Change syntax for passing in template objects to Components to use `{}`

    Right now, passing an object argument to a can.Component involves putting a plain string in an attribute, like so:

    <can-didgeridoo state="state"></can-didgeridoo>
    

    With the template rendered like:

    can.view("#mytemplate", {state: {foo: 1, bar: 2}});
    

    Note that, in this case, the "state" string will be interpreted differently by the can.Component depending on whether you set the default value to state: "@", in its scope.

    I propose the following alternative for passing mustache context values into can.Component:

    <can-didgeridoo state="{{state}}" name="name"></can-didgeridoo>
    

    Where "{{state}}" will automatically look that value up and pass it into the component, and "name" will pass the string directly into the component.

    I believe this is clearer, and will also remove the need to use "@" to configure whether we should interpret it as a string or look it up.

    enhancement fixed in branch 
    opened by zkat 36
  • Application structuring - high level component and route glue

    Application structuring - high level component and route glue

    VOTE HERE

    There's a need to make the high-level behavior of an application easier to manage. Features might include:

    • [ ] - progressive loading of modules / components
    • [ ] - initialization of modules / components
    • [ ] - animating / switching between pages

    Some of this might be accomplishable with #1005. Here's an example:

        can.app({
            "import": function(componentName,callback){
                var script = document.createElement("script");
                script.src = "components/"+componentName.substr(2)+".js";
                script.onload = callback;
                document.body.appendChild(script);
            },
            componentTemplates: {
                "b-contacts": "<b-contacts page='{contactPage}'></b-contacts>",
                "b-contact": "<b-contact contact-id='{contactId}'></b-contact>",
            },
            component: function(){
                return "b-"+can.route.attr("page"); 
            },
            scope: can.route.data,
            animate: function(newContainer, oldContainer, done){
                $(oldContainer).fadeOut();
    
                $(newContainer).css("position","absolute")
                    .css({top: "0px"})
                    .width( $(oldContainer).width() )
                .fadeIn("slow",function(){
                    done();
                    $(newContainer).css({
                        position: "", top: "",width: ""
                    });
                });
    
            },
            element: "main"
        });
    
    Future Feature 
    opened by justinbmeyer 32
  • CanJS 4.0 migration guide

    CanJS 4.0 migration guide

    Changes to watch for

    Stache:

    • %event and other special symbols are now on scope
      • for example, %event is now scope.event
    • can-view-scope doesn't do implicit scope walking, so change to use ../ and whatnot. Or use {{scope.find('foo')}}

    Routes:

    • can.route(":page", { page: "home" }); is now can.route("{page}", { page: "home" });
    • can.route.ready(); is now can.route.start();
    • can.route() is now can.route.register()

    Packages

    • can-stache/helpers/route is now can-stache-route-helpers

    Code/ViewModels

    • can.batch.start() is now can.queues.batch.start()
    • can.batch.stop() is now can.queues.batch.stop()
    documentation 
    opened by JaneOri 30
  • can-semijs

    can-semijs

    The following is a very rough idea of a template engine:

    import helpers from "my-helpers";
    import studentView from "student-view.semijs";
    
    export default (viewModel) => {
    <ul>
       for(let classRoom of viewModel.classRooms) {
         <li class=classRoom.type;>
           let teacher = classRoom.teacher;
           <p> Name: classRoom.name; </p>
           <p> Teacher: teacher.name; </p>
           <p> if( !teacher.hasKeys( classRoom ) ) { No keys } else { Keys } </p>
           <p> helpers.prettyDate( classRoom.startTime ); </p>
         </li>
       }
    </ul>
    };
    

    Notes:

    • this uses ; to signal the end of a JS expression.
    • it also uses identifier( ... ) { ... } to signal a JS expression.

    Pros:

    • Even more like JS.
    • Uses only one ending identifier to signal an insert expression ;. I like this A LOT more than { } because JavaScript already uses {} so I've never thought {} was a good language switch "identifier".

    Cons:

    • Much harder to make work without creating a lot more code.
    • Might be impossible to parse. We'd have to parse backwards from ;. How do you know if let teacher = classRoom.teacher; is {#let teacher be classRoom.teacher} or let teacher be {classRoom.teacher}.
    opened by justinbmeyer 28
  • Modify key -> argument behavior in can.stache

    Modify key -> argument behavior in can.stache

    Orignal Post

    As far as I can tell, I cannot pass a function directly to a component because it sees it as a compute and tries to run it. I have to pass an object or wrap the function in a function instead which isn't always convenient.

    http://jsbin.com/domutinoze/1/edit?html,js,console

    Summary

    We are proposing a COMPUTE ~ and AT @ operator. ~ would try to provide a "compute", while @ would give directly whats AT the specified property. The following table describes its behavior.

    Uses of Keys:

    • helper expression - The arguments passed to stache helpers like {{myHelper key1 key2}}.
    • call expression - The arguments passed to subexpressions like {{myHelper(key1,key2)}}.
    • components - The .attr value that will be set in the component's viewModel for bindings like [attr]="key".
    • method helper expression - The arguments passed to an (event) binding like ($click)="method key".

    Key values:

    Computes

    An observable chain that ends in a compute. Examples for foo.bar:

    // a compute as a property
    {foo: {bar: can.compute(1)}}
    
    // a compute as a map attr
    new can.Map({ foo: {bar: can.compute(1)} })
    
    // a compute returned by a function
    {foo: function(){  return {bar: can.compute(1)} }} 
    
    Functions

    An observable chain that ends in a function or method. Examples for foo.bar:

    // A method that reads an observable
    {foo: {bar: function(){ return map.attr("value") }}}
    
    // A method of an observable
    var MyMap = Map.extend({bar: function(){  return this.attr("value") }})
    {foo: new MyMap()}
    
    // A property of an observable
    new can.Map({ foo: {bar: function(){...} } })
    
    Properties

    An observable chain that ends in a property on an attr that is not a function or compute. Examples for foo.bar:

    // an observable property
    new can.Map({foo: {bar: "value"}})
    
    // An observable returned by a function
    {foo: function(){  return new can.Map({bar: "value"}) }}
    

    Resulting behaviors:

    • R - Reference
    • R() - Executes the reference to get the value
    • (R) - Wraps the observable chain in a compute
    • (!R) - Wraps the observable chain in a compute only if an observable was read
    • {} - Listen to changes and re-execute.

    Behavior table

    | key | computes | functions | properties | general behavior | | --- | --- | --- | --- | --- | | helpers | (R()) | 1 | (R) | pass a compute if possible | | subexpression | {R()} | {R()} | {R} | pass the return value of a compute or function, re-call if something observable changes. | | components | {R()} | {R()} | {R} | two way bind to a compute or map.attr, 1-way bind to a function | | methods | R() | R() | R | pass the return value of a compute or function |

    • 1 - If the key is a function on a normal object, the function is passed, even if the function calls a compute. If the key is a function on a Map prototype, a compute() is passed regardless if the method is compute-able or undefined is returned and not compute-able. If key is a function on a Map attribute, a compute is passed whose value is the function.

    | ~key | computes | functions | properties | general behavior | | --- | --- | --- | --- | --- | | helpers | (R()) | (!R()) | (R) | pass a compute if possible | | subexpression | (R()) | (!R()) | (R) | pass a compute if possible | | components | (R()) | (!R()) | (R) | 1-way bind a compute as a value if possible | | methods | (R()) | (!R()) | (R) | pass a compute if possible |

    | @key | computes | functions | properties | general behavior | | --- | --- | --- | --- | --- | | helpers | {(R)} | {(R)} | {(R)} | pass a compute that returns a a function or compute at the end of the path. | | subexpression | {R} | {R} | {R} | pass a reference, but re-call if reference changes | | components | {R} | {R} | {R} | two-way bind to the reference | | methods | R | R | R | pass the reference |

    Behavior examples

    key / helpers / computes

    // Context
    context = new can.Map({foo: {bar: can.compute(1) }}
    
    // compute passed for `foo.bar` argument:
    compute(function(set){
      return context.attr("foo").attr("bar")(set)
    })
    

    key / components / properties

    // Context
    context = new can.Map({foo: {bar: "value" }}
    
    // viewModel set for `prop="{foo.bar}"`:
    viewModel.attr("prop", "value" )
    

    ~key / components / properties

    // Context
    context = new can.Map({foo: {bar: "value" }}
    
    // viewModel set for `prop="{~foo.bar}"`:
    viewModel.attr("prop", compute(function(set){
      return map.attr("foo").attr("bar",set)
    }) )
    

    @ key / components / functions

    // Context
    function bar(){ ... }
    var MyMap = Map.extend({bar: bar})
    context = new Map({foo: new MyMap()}
    
    // viewModel set for `[(prop)]="foo@bar"`:
    viewModel.attr("prop", bar ) // if context.attr("foo") changes, a different function can be set here.
    
    
    enhancement solved on paper 
    opened by dylanrtt 28
  • create can.Component for custom tags

    create can.Component for custom tags

    Background:

    • https://dvcs.w3.org/hg/webcomponents/raw-file/tip/explainer/index.html

    I'd like to start making it possible to create custom tags similar to webcomponents.

    For example:

    <overlay displayWhen="userIsLoggedIn" class="{{classHelper foo}}"><h1> Hello World</h1></overlay>
    

    powered by something like

    can.Component("Overlay", {
      template: "TEMPLATEREF",
      "{displayWhen} change": function(displayWhen, ev, display){
        display? this.element.show() : this.element.hide()
      }
    })
    

    Considerations:

    Merging DOM

    How to merge things setup in the "outer" template like:

    • attributes of the custom tag
    • children of the custom tag

    with the tag's template?

    AMD / Steal nameless modules.

    enhancement 
    opened by justinbmeyer 27
  • can-import self closing tag on css/less

    can-import self closing tag on css/less

    A self-closing tag should be accepted for css/less

    <can-import from="somfile.less!"></can-import>
    

    to

    <can-import from="somfile.less!"/>
    

    There will never be content.

    Currently if you do this:

    {{#if xyz}}
    <can-import from="somfile.less!"/>
    {{/if}}
    

    The css/less file is loaded even when xyz is false, unless you don't use a self closing tag.

    opened by MarcGodard 26
  • Validation improvements

    Validation improvements

    VOTE HERE

    It seems like can/map/validate is sort of like can/map/define::setter but has several differences, and it might make sense to merge them.

    Setter supports async, validations doesn't.

    Validations supports an "errors" object and "errors" events, both of which are very useful.

    I propose merging the validations plugin into define. Or at least making them work together rather than separately.

    A couple thoughts:

    • Although validate would be similar to set, I think validate should be separate, because I can think of cases where you'd want the hook provided by set and validation logic separate.
    • The validate callback should be called with a success, error so you can do serverside validations
    • errors should be observable (#355)
    enhancement 
    opened by moschel 26
  • Possible memory leak

    Possible memory leak

    Hi!

    I think I've found a memory leak. JS Bin

    To reproduce the leak:

    1. Take a heap snapshot
    2. Click on Insert
    3. Click on Remove
    4. Take a heap snapshot
    5. Click on Insert
    6. Click on Remove
    7. Take a heap snapshot

    Now view the list of objects created between the first and the second snapshot. You'll see that there are items which cannot be garbage collected: image

    When I discovered the issue I was using Chrome 56.... I don't know the exact version because when I tried to check my Chrome version it started to update to 57.0.2987.133. I had no choice it upgraded to the latest stable version. The problem still exists with Chrome 57.0.2987.133.

    In the JS Bin I use a custom build. Here are the versions for the modules I use in the custom build: can-component: 3.0.7 can-route: 3.0.8 can-stache: 3.0.21 can-stache-bindings: 3.0.13 can-stache-converters: 3.0.7 can-compute: 3.0.7 can-event: 3.2.0 can-view-model: 3.1.3 can-connect/can/base-map/base-map: 1.3.8 can-define/map/map: 1.0.17 can-define/list/list: 1.0.17 can-set: 1.1.0 can-fixture: 1.0.13 can-map: 3.0.6 can-list: 3.0.3 can-map-backup: 3.0.3 can-map-define: 3.0.6 can-connect/can/model/model: 1.3.8 can-jquery: 3.0.6

    Thanks!

    opened by sszabolcs 25
  • Figure out attribute binding syntaxes

    Figure out attribute binding syntaxes

    In combination with #1699, this proposal seeks to create a more flexible, powerful, and easily understood attribute binding syntaxes for use in stache.

    Summary

    | Type | Example | | --- | --- | | event - viewModel | <my-comp (child-event)="parentMethod()"/> | | event - DOM | <my-comp ($click)="parentMethod()"/> | | 0 way - viewModel | <my-comp child-prop="foo"/> | | one way - viewModel - parent to child | <my-comp {child-prop}="parentProp"/> | | one way - DOM - parent to element | <my-comp {$el-prop}="parentProp"/> | | one way - reference - child to reference | <my-comp {^child-prop}="*ref"/> | | two way - viewModel | <my-comp {(child-prop)}="parentProp"/> | | two way - DOM | <my-comp {($child-prop)}="parentProp"/> | | two way - reference | <my-comp {(child-prop)}="*ref"/> | | two way - reference shorthand | <my-comp *ref/> |

    event - viewModel

    (event-name)="StacheMethodExpression"

    Binds an event on the can.viewModel of whatever element it was placed on.

    Example:

    <modal (todo.created)="hideModal()" (cancelled)="hideModal()"/>
    

    event - DOM

    ($event-name)="StacheMethodExpression"

    Bind an event on the element it was placed on.

    Example:

    <button ($click)="todo.save()">Save</button>
    

    0 way - viewModel

    view-model-attr="value"

    Sets the viewModelAttr property to "value".

    one way - viewModel - parent to child

    The following looks up task in the scope, and sets it as todo in the <modal>'s viewModel:

    <modal {todo}="task"/>
    

    one way - DOM - parent to element

    Provides one-way binding to an element's property or attribute. We will maintain a list of properties that will be set instead of setting the attribute.

    <input {$checked}="complete" type='checkbox'/>
    

    This is equivalent to:

    <input {{#complete}}checked{{/complete}} type='checkbox'/>
    

    While it's possible to do one-way binding to an element property or attribute with stache alone, two-way binding uses this for syntactic sugar.

    one way - reference - child to reference

    The following looks up task in the child viewModel, and sets it as todo in the current template's reference scope:

    <modal {^task}="*todo"/>
    

    two way - viewModel

    This two-way binds a viewModel property to something in the scope. The following two-way binds <component>'s childProp to parentProp in the scope:

    <component  {(child-prop)}="parentProp" />
    

    This is syntactic sugar for:

    <component  {childProp}="parentProp"
               (childProp)="~parentProp(%viewModel.childProp)" />
    

    two way - DOM

    This two-way binds a element property to something in the scope. The following two-way binds the <input>'s checked property to complete in the scope:

    <input {($checked)}="complete" type='checkbox' />
    

    This is syntactic sugar for:

    <component  {$checked}="complete"
               (change)="~complete($element.checked)" />
    

    A mapping of property names to which event should be listened to will be kept.

    two way - reference

    This two-way binds a element property to something in the scope. The following two-way binds the <component>'s selected.licensePlate property to selectedPlate in the template references scope:

    <component {(selected.license-plate)}="*selectedPlate"/>
    

    This is syntactic sugar for:

    <component  {selected.license-plate}="*selectedPlate"
               (selected.licensePlate)="~*selectedPlate(%viewModel.selected.licensePlate)" />
    
    opened by justinbmeyer 25
  • docs: Fix a few typos

    docs: Fix a few typos

    There are small typos in:

    • docs/can-guides/introduction/comparison.md
    • docs/can-guides/introduction/technical.md
    • docs/can-guides/topics/forms.md

    Fixes:

    • Should read pizzazz rather than pizzaz.
    • Should read observable rather than obserable.
    • Should read identifying rather than indentifying.
    • Should read easier rather than easer.

    Semi-automated pull request generated by https://github.com/timgates42/meticulous/blob/master/docs/NOTE.md

    opened by timgates42 0
  • logWhatChangesMe isn't getting getter derived observables

    logWhatChangesMe isn't getting getter derived observables

    I have a functionon a StacheElement like:

    	get isEven(){
    		return (this.count % 2) === 0;
    	}
    

    logWhatChangesMe is not reporting count as a source. However, you can see it is source internally:

    image

    And the following works:

    image
    opened by justinbmeyer 0
  • createinstance and updateinstance in BaseConnection::save are not atomic.

    createinstance and updateinstance in BaseConnection::save are not atomic.

    When createInstance or updateInstance is called in "save: function(instance){}" they are not batched. As such if you have an observation on an object-instance, you can get multiple calls for each key/member/field/prop.

    Fictional example case: Assume an Object that has to following fields: "GUID, ID, name". To create a new object you only submit "Name" to the server. The server then replies with {"GUID":"0F5581" , "ID":1, name: "Name}. If you now create an observation of that object on GUID and ID, your observation will be trigger twice. If you then required both a valid GUI and ID at that point in time, you will get an error since ID hasn't been updated yet.

    Consider adding stop and start batch in these positions. (I needed to add this for my GUI code to work, the update/creation had to be atomic from the point of the observer.)

    opened by qantourisc 5
  • can-control cannot set up delegate listeners on observables.

    can-control cannot set up delegate listeners on observables.

    In can 2.x this property on a can-control would bind to a delegated handler in a can-map:

        '{pageObserve} headerId change': function(o, ev, prop, how, newVal, oldVal) {
            if ( how === "add" ) {
               // ...
            }
        },
    

    and fire this "change" event handler on options.pageObserve only when the headerId property changed.

    This was made possible by can/map/delegate, which in modern CanJS is no longer part of can-map or the overall CanJS event binding and dispatch system. CanMap no longer has a delegate() prototype method and can-event-queue/map/map's on function, used by can-control, can only delegate to DOM targets, not to observables. The result is that after upgrading a 2.x application to Can 6, this event handler no longer fires.

    bug regression 6.0 
    opened by bmomberger-bitovi 0
Releases(v6.6.2)
Owner
CanJS
Libraries and frameworks that empower JS development. We Can JS!
CanJS
AngularJS - HTML enhanced for web apps!

AngularJS AngularJS lets you write client-side web applications as if you had a smarter browser. It lets you use good old HTML (or HAML, Jade/Pug and

Angular 59.3k Jan 4, 2023
Cybernetically enhanced web apps

What is Svelte? Svelte is a new way to build web applications. It's a compiler that takes your declarative components and converts them into efficient

Svelte 64.3k Dec 28, 2022
A framework for building native apps with React.

React Native Learn once, write anywhere: Build mobile apps with React. Getting Started · Learn the Basics · Showcase · Contribute · Community · Suppor

Facebook 106.8k Jan 3, 2023
🙋‍♀️ 3kb library for tiny web apps

3kb library for tiny web apps. Sometimes, all you want to do is to try and do something—No boilerplate, bundlers, or complex build processes. Lucia ai

Aiden Bai 699 Dec 27, 2022
HTML Framework that allows you not to write JavaScript code.

EHTML (or Extended HTML) can be described as a set of custom elements that you can put on HTML page for different purposes and use cases. The main ide

Guseyn Ismayylov 171 Dec 29, 2022
Example code demonstrating how to "upsert" (update or insert) records to an Airtable table in various languages

Airtable Upsert Examples This repository contains examples demonstrating how to "upsert" (update or insert) records to an Airtable table in various pr

Airtable Labs 5 Dec 5, 2022
Prisma is a next-generation object–relational mapper (ORM) that claims to help developers build faster and make fewer errors.

This is a Next.js project bootstrapped with create-next-app. Getting Started First, run the development server: npm run dev # or yarn dev Open http://

Rhodin Emmanuel Nagwere 1 Oct 8, 2022
An open-source, self-hosted, low-code framework to build internal tools, web apps, admin panels, BI dashboards, workflows, and CRUD apps with YAML or JSON.

An open-source, self-hosted, low-code framework to build internal tools, web apps, admin panels, BI dashboards, workflows, and CRUD apps with YAML or JSON.

Lowdefy 2k Jan 4, 2023
Build your own generative art NFT collection with 21 lines of JavaScript

Avatar Collection Build your own Generative Art NFT Collection in 1 minute. Quickstart Just run the following to get started: git clone https://github

rarepress 79 Dec 16, 2022
🏗 Build static blog with lines of HTML and Markdown.

Nimblog Nimblog requires only a few lines of HTML to deploy and is suitable for lightweight bloggers. The official guide is built with Nimblog, check

Chell 7 Dec 19, 2022
Single Page Application micro framework. Views, routes and controllers in 60 lines of code

SPApp Single Page Application Micro Framework Supports views, controllers and routing in 60 lines of code! Introduction If you heard anything about MV

Andrew 262 Nov 23, 2022
Perfect SvelteKit dark mode in 2 lines of code. Support System preference and any other theme with no flashing

This library is a port of next-theme for SvelteKit. All credit goes to pacocoursey and all next-themes contributors While usable, this library is stil

null 42 Sep 30, 2022
A fast and optimized middleware server with an absurdly small amount of code (300 lines) built on top of Deno's native HTTP APIs

A fast and optimized middleware server with an absurdly small amount of code (300 lines) built on top of Deno's native HTTP APIs with no dependencies. It also has a collection of useful middlewares: log file, serve static, CORS, session, rate limit, token, body parsers, redirect, proxy and handle upload. In "README" there are examples of all the resources. Faster's ideology is: all you need is an optimized middleware manager, all other functionality is middleware.

Henrique Emanoel Viana 19 Dec 28, 2022
🚀 A mongoose plugin to monetize your apis in few lines of code

Stripe Mongoose Api Stripe Mongoose Api is a Mongoose plugin that simplifies building checkout and payment system for apis with stripe. It will provid

Moscatelli Marco 13 Dec 29, 2022
Get the latest Flashbots blocks and Flashbots transactions using TypeScript in two lines of code !

mev-blocks-js This package can let you query the Flashbots blocks API easily from any JavaScript or TypeScript project. You can access the Flashbots b

Luca G.F. 6 May 14, 2022
Find out how many lines of code you have written for your project 📜

?? TLOC (Tomper Lines Of Code) Find out how many lines of code you have written for your project. ?? Installation (Install the package globally) npm i

Varun Tiwari 9 Oct 17, 2022
Capable Langchain/AutoGPT alternative in ~350 lines of core code

??️ ?? BingChain This is an evolution of langchain-mini, a very simple re-implementation of LangChain, in ~350 lines of core code. In essence, it is a

Postman Open Technologies 19 Jul 30, 2023
🦜️🔗 This is a very simple re-implementation of LangChain, in ~100 lines of code

??️ ?? LangChain-mini This is a very simple re-implementation of LangChain, in ~100 lines of code. In essence, it is an LLM (GPT-3.5) powered chat app

Colin Eberhardt 204 Aug 14, 2023
Sample apps showing how to build music and video apps for Xbox using a WebView.

description languages name page_type products urlFragment Sample showing how to build music and video apps using primarily web technologies for Xbox.

Microsoft 11 Dec 14, 2022
The Power CAT code components are a set of Power Apps component framework (PCF) controls that can be used to enhance power apps.

Power CAT code components The Power CAT code components are a set of Power Apps component framework (PCF) controls that can be used to enhance power a

Microsoft 70 Jan 2, 2023